我正在尝试遍历两个 Firebase 数据库引用,firstRef
和 secondRef
,使用 observeSingleEvent
Firebase 异步方法观察各自的值,并将值附加到两个数组 firstArray
和 secondArray
。完成后,我想通知调度组并执行完成处理程序。但是,当调用以下方法时,这两个数组总是意外地发现 nil。我不太清楚为什么会这样,或者是否会出现这个问题,因为我嵌套了异步函数。我知道强制展开在语法上也不受欢迎,但是,在这种情况下,我希望这两个数组始终填充从数据库中检索到的数据。
func loop(inputArray: [inputType], doneLoop: @escaping (_ firstArray: [firstType],_ secondArray: [secondType]) -> Void) {
var firstArray: [firstType]?
var nameArray: [secondType]?
let dispatchGroup = DispatchGroup()
for element in inputArray {
let firstRef = Database.database().reference(withPath: "firstPath")
//Enter dispatch group
dispatchGroup.enter()
firstRef.observeSingleEvent(of: .value, with: { snapshot in
//Storing first snapshot value
let firstSnapshotValue = snapshot.value as! firstType
let secondRef = Database.database().reference(withPath: "secondPath")
secondRef.observeSingleEvent(of: .value, with: { snapshot in
//Storing second snapshot value
let secondSnapshotValue = snapshot.value as? String
//Append retrieved values to arrays
firstArray?.append(firstSnapshotValue)
secondArray?.append(secondSnapshotValue)
})
})
//Leave dispatch group
dispatchGroup.leave()
}
//Notify on main queue and execute completion handler
dispatchGroup.notify(queue: .main) {
doneLoop(firstArray!, secondArray!)
}
}
我是否需要创建一个带有@escaping 完成处理程序的新函数?唯一的问题是,由于它在数组中循环,完成只会执行一次,因此只会填充一个值。
如有任何帮助,我们将不胜感激!
最佳答案
你应该同时制作firstArray
和nameArray
:
var firstArray = [firstType]()
var nameArray = [secondType]()
leave()
dispatchGroup
在最里面的回调中。并考虑将其包装在 defer{}
中,以防止将来在回调中出现任何多路径。
func loop(inputArray: [inputType], doneLoop: @escaping (_ firstArray: [firstType],_ secondArray: [secondType]) -> Void) {
var firstArray = [firstType]()
var nameArray = [secondType]()
let dispatchGroup = DispatchGroup()
for element in inputArray {
let firstRef = Database.database().reference(withPath: "firstPath")
//Enter dispatch group
dispatchGroup.enter()
firstRef.observeSingleEvent(of: .value, with: { snapshot in
//Storing first snapshot value
let firstSnapshotValue = snapshot.value as! firstType
let secondRef = Database.database().reference(withPath: "secondPath")
secondRef.observeSingleEvent(of: .value, with: { snapshot in
//Leave dispatch group
defer { dispatchGroup.leave() }
//Storing second snapshot value
let secondSnapshotValue = snapshot.value as? String
//Append retrieved values to arrays
firstArray.append(firstSnapshotValue)
secondArray.append(secondSnapshotValue)
})
})
}
//Notify on main queue and execute completion handler
dispatchGroup.notify(queue: .main) {
doneLoop(firstArray, secondArray)
}
}
此外,如果 secondRef
的值是独立的,请考虑取消嵌套内部 observeSingleEvent
调用(并添加额外的 enter()
和 leave()
调用)。
并发考虑
照原样,您的代码可能/最终会丢失对 firstArray
和 secondArray
的写入。 Firebase 的 observeSingleEvent
执行其 with
block 的速度越快,数据丢失的速度就越快。为避免这种情况,所有写入(append
)都应从串行队列完成:
let queue = DispatchQueue(label: "tld.company.app.queue")
queue.async() {
// Write
}
queue.sync() {
// Read
}
或者,更好的是,使用 .barrier
标志保持读取并发:
let queue = DispatchQueue(label: "tld.company.app.queue", attributes: .concurrent)
queue.async(flags: .barrier) {
// Write
}
queue.sync() {
// Read
}
关于swift - 如何在嵌套的 Firebase 异步 observeSingleEvent() 方法 Swift 中使用 DispatchGroup?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57865453/