Pooling completion handlers together such that met

2020-02-15 06:49发布

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.

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.

标签: ios swift3
1条回答
地球回转人心会变
2楼-- · 2020-02-15 07:06

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

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.

查看更多
登录 后发表回答