将完成处理程序汇集在一起​​,以便一旦执行多个闭包,方法就完成 [英] Pooling completion handlers together such that method completes once multiple closures are executed

查看:101
本文介绍了将完成处理程序汇集在一起​​,以便一旦执行多个闭包,方法就完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种情况,我想并行执行三个不同的异步任务.一旦完成所有三个任务,我便希望调用方法意识到这一点并调用它自己的完成处理程序.

I have a scenario where I want to perform three distinct asynchronous tasks in parallel. Once all three tasks are complete, I then want the calling method to be aware of this and to call its own completion handler.

以下是此逻辑的非常简化的版本:

Below is a very simplified version of the logic for this:

class ViewController: UIViewController {
    func doTasks(with object: Object, completionHandler: () -> Void) {
        // Once A, B & C are done, then perform a task
        wrapupTask()
        // When task is complete, call completionHandler
        completionHandler()
    }
}

fileprivate extension ViewController {
    func taskA(with object: Object, completionHandler: () -> Void) {
        // Do something

        completionHandler()
    }

    func taskB(with object: Object, completionHandler: () -> Void) {
        // Do something

        completionHandler()
    }

    func taskC(with object: Object, completionHandler: () -> Void) {
        // Do something

        completionHandler()
    }
}

我可以轻松地将处理程序链接在一起,但是任务可能会花费更长的时间,并且代码会很烂.

I could easily chain the handlers together, but then the task will likely take longer and the code will suck.

我考虑的另一个项目是一个简单的计数器,该计数器在每次任务完成时都会递增,然后一旦达到3,便会通过类似以下方式调用wrapupTask():

Another item I considered was a simple counter that incremented each time a task completed, and then once it hit 3, would then call the wrapupTask() via something like this:

var count: Int {
   didSet {
      if count == 3 {
         wrapupTask()
      }
   }
}

我考虑过的另一种选择是创建一个操作队列,然后将任务加载到其中,并具有运行我的包装任务的时间的依赖性.队列为空后,它将调用完成处理程序.但是,这似乎比我想要完成的工作要复杂得多.

Another option I have considered is to create an operation queue, and to then load the tasks into it, with a dependency for when to run my wrap up task. Once the queue is empty, it will then call the completion handler. However, this seems like more work than I'd prefer for what I want to accomplish.

我希望我缺少一些更好的东西.

My hope is that there is something better that I am just missing.

推荐答案

仅需了解OOPer所说的内容,您正在寻找DispatchGroup.在下面,对taskAtaskBtaskC的调用是伪代码,但其他所有内容都是真实的:

Just to pick up on what OOPer said, you are looking for DispatchGroup. In the following, the calls to taskA, taskB, and taskC are pseudo-code, but everything else is real:

func doTasks(with object: Object, completionHandler: () -> Void) {
    let group = DispatchGroup()
    group.enter()
    taskA() {
        // completion handler
        group.leave()
    }
    group.enter()
    taskB() {
        // completion handler
        group.leave()
    }
    group.enter()
    taskC() {
        // completion handler
        group.leave()
    }
    group.notify(queue: DispatchQueue.main) {
        // this won't happen until all three tasks have finished their completion handlers
        completionHandler()
    }
}

每个enter在异步完成处理程序的末尾都由leave进行匹配,只有当所有匹配项都已实际执行后,我们才进入notify完成处理程序.

Every enter is matched by a leave at the end of the asynchronous completion handler, and only when all the matches have actually executed do we proceed to the notify completion handler.

这篇关于将完成处理程序汇集在一起​​,以便一旦执行多个闭包,方法就完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆