Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.8k views
in Technique[技术] by (71.8m points)

ios - Pooling completion handlers together such that method completes once multiple closures are executed

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share

2.1m questions

2.1m answers

63 comments

56.5k users

...