我对实现此目标的最佳方法感到困惑。我试图通过网络调用保持循环运行并加在一起的Double值的总数。我读过的所有内容都说要使用DispatchGroup。我的完成呼叫要么为时过早,要么根本不被呼叫,我尝试了我能想到的.enter,.leave和.wait的每种配置。
{{1}}
答案 0 :(得分:1)
您应该等待所有组任务完成,然后再调用完成块。
像下面一样。
var runningTotal: Double = 0.00
ref.observeSingleEvent(of: .value) { (snapshot) in
guard let bills = snapshot.value as? [String: AnyObject] else {
//error
return
}
let group = DispatchGroup()
for billId in bills.keys {
group.enter()
print("Entering")
Database.database().reference().child("bills").child(billId).observeSingleEvent(of: .value, with: { (snapshot) in
guard let bill = snapshot.value as? [String: AnyObject] else {
group.leave()
return
}
if let amount = bill["amount"] as? Double {
runningTotal += amount
}
group.leave()
print("Leaving")
})
}
group.wait()
completion(runningTotal)
}
答案 1 :(得分:1)
一些想法:
避免从主线程调用wait
。该用例非常有限。 notify
是实现同一目标的更安全的方法。
确保从循环中的每个路径调用leave
。使用defer
块可以很好地实现这一点。
所以:
func foo(completion: @escaping (Double?) -> Void) {
ref.observeSingleEvent(of: .value) { snapshot in
guard let bills = snapshot.value as? [String: AnyObject] else {
//error
completion(nil)
return
}
let group = DispatchGroup()
var runningTotal = 0.0
for billId in bills.keys {
group.enter()
print("Entering")
Database.database().reference().child("bills").child(billId).observeSingleEvent(of: .value) { snapshot in
defer { group.leave() }
guard let bill = snapshot.value as? [String: AnyObject] else {
return
}
if let amount = bill["amount"] as? Double {
runningTotal += amount
}
print("Leaving")
}
}
group.notify(queue: .main) {
completion(runningTotal)
}
}
}