如何在嵌套的 Firebase 异步 observeSingleEvent() 方法 Swift 中使用 DispatchGroup?
How do I use DispatchGroup within nested Firebase asynchronous observeSingleEvent() methods Swift?
我正在尝试遍历两个 Firebase 数据库引用 firstRef
和 secondRef
,使用 observeSingleEvent
Firebase 异步方法观察各自的值,并将这些值附加到两个数组, firstArray
和 secondArray
。完成后,我想通知调度组并执行完成处理程序。然而,当调用下面的方法时,两个数组总是unexpectedly found 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()
调用)。
并发考虑
照原样,您的代码将 potentially/eventually 丢失对 firstArray
和 secondArray
的写入。 Firebase 的 observeSingleEvent
执行其 with
块的速度越快,数据丢失的速度就越快。为避免这种情况,所有写入 (append
s) 都应从串行队列完成:
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
}
阅读更多:Create thread safe array in Swift
我正在尝试遍历两个 Firebase 数据库引用 firstRef
和 secondRef
,使用 observeSingleEvent
Firebase 异步方法观察各自的值,并将这些值附加到两个数组, firstArray
和 secondArray
。完成后,我想通知调度组并执行完成处理程序。然而,当调用下面的方法时,两个数组总是unexpectedly found 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()
调用)。
并发考虑
照原样,您的代码将 potentially/eventually 丢失对 firstArray
和 secondArray
的写入。 Firebase 的 observeSingleEvent
执行其 with
块的速度越快,数据丢失的速度就越快。为避免这种情况,所有写入 (append
s) 都应从串行队列完成:
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
}
阅读更多:Create thread safe array in Swift