Swift-在调用完成处理程序swift之前等待异步for-in循环完成

时间:2019-01-22 01:32:46

标签: swift firebase firebase-realtime-database grand-central-dispatch

我对实现此目标的最佳方法感到困惑。我试图通过网络调用保持循环运行并加在一起的Double值的总数。我读过的所有内容都说要使用DispatchGroup。我的完成呼叫要么为时过早,要么根本不被呼叫,我尝试了我能想到的.enter,.leave和.wait的每种配置。

{{1}}

2 个答案:

答案 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)

一些想法:

  1. 避免从主线程调用wait。该用例非常有限。 notify是实现同一目标的更安全的方法。

  2. 确保从循环中的每个路径调用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)
        }
    }
}