gpt4 book ai didi

ios - 火存储 : Calls with of async function with SnapshotListener and in a cycle with DispatchGroup cause a crash

转载 作者:行者123 更新时间:2023-11-29 05:40:13 31 4
gpt4 key购买 nike

我在将 DispatchGroup (因为它是 recommended here )与 FireStore snapshotListener 一起使用时遇到问题

在我的示例中,我有两个函数。第一个由 ViewController 调用,并应返回要在 View 中显示的对象数组。第二个是从 FireStore 为每个数组成员获取子对象的函数。它们都必须异步执行。第二个应该循环调用。

因此我使用 DispatchGroup 等待第二个函数的所有执行完成后调用 UI 更新。这是我的代码(请参阅评论部分):

/// Async function returns all tables with active sessions (if any)
class func getTablesWithActiveSessionsAsync(completion: @escaping ([Table], Error?) -> Void) {

let tablesCollection = userData
.collection("Tables")
.order(by: "name", descending: false)

tablesCollection.addSnapshotListener { (snapshot, error) in
var tables = [Table]()

if let error = error {
completion (tables, error)
}

if let snapshot = snapshot {
for document in snapshot.documents {
let data = document.data()
let firebaseID = document.documentID
let tableName = data["name"] as! String
let tableCapacity = data["capacity"] as! Int16

let table = Table(firebaseID: firebaseID, tableName: tableName, tableCapacity: tableCapacity)
tables.append(table)
}
}

// Get active sessions for each table.
// Run completion only when the last one is processed.
let dispatchGroup = DispatchGroup()

for table in tables {
dispatchGroup.enter()
DBQuery.getActiveTableSessionAsync(forTable: table, completion: { (tableSession, error) in
if let error = error {
completion([], error)
return
}
table.tableSession = tableSession
dispatchGroup.leave()
})
}
dispatchGroup.notify(queue: DispatchQueue.main) {
completion(tables, nil)
}
}
}

/// Async function returns table session for table or nil if no active session is opened.
class func getActiveTableSessionAsync (forTable table: Table, completion: @escaping (TableSession?, Error?) -> Void) {

let tableSessionCollection = userData
.collection("Tables")
.document(table.firebaseID!)
.collection("ActiveSessions")

tableSessionCollection.addSnapshotListener { (snapshot, error) in
if let error = error {
completion(nil, error)
return
}
if let snapshot = snapshot {
guard snapshot.documents.count != 0 else { completion(nil, error); return }

// some other code

}
completion(nil,nil)
}
}

由于在第二个函数中使用了 snapshotListener,直到快照发生更改为止一切正常。当数据更改时,将调用以下闭包:

DBQuery.getActiveTableSessionAsync(forTable: table, completion: { (tableSession, error) in
if let error = error {
completion([], error)
return
}
table.tableSession = tableSession
dispatchGroup.leave()
})

它在dispatchGroup.leave()步骤上失败,因为此时组是空的。

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

所有的dispatchGroup.enter()和dispatchGroup.leave()都已经在这一步完成了。这个闭包是由监听器单独调用的。

我试图找到如何检查 DispatchGroup 是否为空以不调用leave()方法的方法。但没有找到任何原生解决方案。我发现的唯一类似的解决方案是在 following answer 中。但它看起来太老套了,不确定是否能正常工作。

有没有办法检查DispatchGroup是否为空?根据this的回答,没有办法。但过去两年可能发生了一些变化。

是否有其他方法可以解决此问题并保持 snapshotListener 不变?

最佳答案

现在我实现了某种解决方案 - 使用计数器。我不认为这是最好的解决方案,但至少目前有效。

// Get active sessions for each table.
// Run completion only when the last one is processed.
var counter = tables.count

for table in tables {
DBQuery.getActiveTableSessionAsync(forTable: table, completion: { (tableSession, error) in
if let error = error {
completion([], error)
return
}
table.tableSession = tableSession

counter = counter - 1
if (counter <= 0) {
completion(tables, nil)
}
})
}

关于ios - 火存储 : Calls with of async function with SnapshotListener and in a cycle with DispatchGroup cause a crash,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56630285/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com