【问题标题】:Swift- Waiting for asynchronous for-in loop to complete before calling completion handler swiftSwift-在调用完成处理程序之前等待异步for-in循环完成
【发布时间】:2019-01-22 01:32:46
【问题描述】:

我不知道实现这一目标的最佳方法是什么。我试图通过网络调用保持我循环并添加在一起的 Double 值的运行总数。我读过的所有内容都说要使用 DispatchGroup。我的完成要么调用得太早,要么根本没有被调用,我已经尝试了所有我能想到的 .enter、.leave 和 .wait 配置。

    let group = DispatchGroup()
    var runningTotal: Double = 0.00

    ref.observeSingleEvent(of: .value) { (snapshot) in
        guard let bills = snapshot.value as? [String: AnyObject] else {
            //error
            return
        }

        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 {
                    return
                }
                if let amount = bill["amount"] as? Double {
                    runningTotal += amount
                }
                group.leave()
                print("Leaving")
            })
        }
        completion(runningTotal)
    }
    group.wait()
}

【问题讨论】:

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


    【解决方案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)
            }
        }
    }
    

    【讨论】:

    • 我应该提一下,我不想在这个调用之后直接返回主线程。调用后直接进入另一个网络函数。
    • 但是你从不想要阻塞主线程。你冒着让看门狗进程杀死你的应用程序的风险,它充其量只是一个不合标准的用户体验。只需在此调用的完成处理程序中调用您的下一个网络调用(或类似的模式)。使用异步模式来实现所需的依赖,而不是阻塞主线程。
    • Rob,似乎仍然立即调用完成:我的打印语句看起来像 Optional(0.0) ,Entering,entering,entering... 等等。
    • 听起来你的 notify 调用不在 observeSingleEvent 闭包内。
    • 好吧,我相信我们现在在同一个页面上。 wait() 是一个阻塞调用,我现在明白了。我想我需要学习的是“避免这种情况的模式”部分。只开发了一年半,所以仍然在学习很多东西......
    【解决方案2】:

    您应该等到所有组任务完成后,再调用完成块。

    如下所示。

        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)
        }
    

    【讨论】:

    • 在尝试这样做时,completion(runningTotal) 在循环一次之前立即返回。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 2020-08-02
    • 1970-01-01
    • 2019-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多