Call completion block when two other completion blocks have been called

后端 未结 2 1310
独厮守ぢ
独厮守ぢ 2020-12-11 22:08

I have a function doEverything that takes a completion block. It calls two other functions, doAlpha and doBeta which both have complet

2条回答
  •  南方客
    南方客 (楼主)
    2020-12-11 22:45

    Grand Central Dispatch (GCD) is a pretty good choice of what are you trying to do here, you can achieve this by using DispatchQueue and DispatchGroup, as follows:

    Swift 3:

    func doEverything(completion: @escaping () -> ()) {
        let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent, target: .main)
        let group = DispatchGroup()
    
        group.enter()
        queue.async (group: group) {
            print("do alpha")
    
            group.leave()
        }
    
        group.enter()
        queue.async (group: group) {
                print("do beta")
    
            group.leave()
        }
    
        group.notify(queue: DispatchQueue.main) {
            completion()
        }
    }
    

    Or, you can implement it this way (which I find more readable):

    func doEverything(completion: @escaping () -> ()) {
        let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent, target: .main)
        let group = DispatchGroup()
    
        queue.async (group: group) {
            print("do alpha")
        }
    
        queue.async (group: group) {
            print("do beta")
        }
    
        group.notify(queue: DispatchQueue.main) {
            completion()
        }
    }
    

    Note that I removed the success flag from the completion closure.

    At this case, "do beta" (the execution of the second queue.async) won't be executed until "do alpha" (the execution of the first queue.async) finished, and that's because queue target is .main. If you want to let both of queue.async work concurrently, there is no need to create an extra queue, the same queue should does the work, by replacing:

    let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent, target: .main)
    

    with:

    let queue = DispatchQueue(label: "reverseDomain", attributes: .concurrent)
    

    Now, the system will control over how both of queue.async tasks should work concurrently (and obviously, group.notify will be executed after the tow of the tasks finish).

    Hope this helped.

提交回复
热议问题