【问题标题】:Dealing with multiple completion handlers处理多个完成处理程序
【发布时间】:2018-05-03 05:02:06
【问题描述】:

我正在尝试为数组中的每个元素协调多个完成处理程序。

代码本质上是这样的:

var results = [String:Int]()

func requestData(for identifiers: [String])
{
    identifiers.forEach
    {   identifier in

        service.request(identifier, completion: { (result) in
            result[identifier] = result
        })
    }

    // Execute after all the completion handlers finish
    print(result)
}

因此,Array 中的每个元素都通过带有完成处理程序的服务发送,并且所有结果都存储在一个数组中。一旦所有这些处理程序完成,我希望执行一些代码。

我试图用DispatchQueue 来做这个

var results = [String:Int]()

func requestData(for identifiers: [String])
{
    let queue = DispatchQueue.init(label: "queue")

    identifiers.forEach
    {   identifier in

        service.request(identifier, completion: { (result) in
            queue.sync
            {
                result[identifier] = result
            }
        })
    }

    // Execute after all the completion handlers finish
    queue.sync
    {
        print(result)
    }
}

但 print 调用仍然首先执行,Dictionary 为空

【问题讨论】:

    标签: swift concurrency completionhandler dispatch-queue


    【解决方案1】:

    如果我了解您要正确执行的操作,您可能想使用DispatchGroup

    这是一个例子:

    let group = DispatchGroup()
    
    var letters = ["a", "b", "c"]
    
    for letter in letters {
        group.enter()
        Server.doSomething(completion: { [weak self] (result) in
            print("Letter is: \(letter)")
            group.leave()
        })
    }
    
    group.notify(queue: .main) {
        print("- done")
    }
    

    这将打印如下内容:

    b
    c
    a
    // ^ in some order
    - done
    

    【讨论】:

    • 我希望我能多次投票。无法相信要找到这个超级有用的内置功能是多么困难!
    【解决方案2】:

    首先,请注意您的service.request(...) 是在异步模式下处理的。另一个问题是你想在那个循环中完成所有的服务请求。

    我的建议是创建带有完成处理程序的函数,并在每个完成的循环上添加一个计数器。您的功能将与以下类似。

    var results = [String:Int]()
    
    func requestData(for identifiers: [String], callback:@escaping (Bool) -> Void)
    {
        var counter = 0
        var maxItem = identifiers.count
    
        identifiers.forEach
        {   identifier in
    
            service.request(identifier, completion: { (result) in
                result[identifier] = result
                counter += 1
                if counter == maxItem {
                    callback(true) // update completion handler to say all loops request are done
                }
                // if not, continue the other request
            })
        }
    }
    

    这就是你的代码的另一部分将如何调用函数并等待回调

    requestData(for identifiers:yourArrays) { (complete) in
    
        if complete {
            print(results)
        }
    }
    

    如果发生错误,不要忘记管理。

    【讨论】:

      猜你喜欢
      • 2013-11-24
      • 1970-01-01
      • 2015-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多