Search code examples
swiftconcurrencycompletionhandlerdispatch-queue

Dealing with multiple completion handlers


I'm trying to coordinate several completion handlers for each element in an array.

The code is essentially this:

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

So each element in the Array is sent through a service with a completion handler, and all the results are stored in an array. Once all of these handlers complete, I wish to execute some code.

I attempted to do this with 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)
    }
}

but the print call is still being executed first, with an empty Dictionary


Solution

  • If I understand what are you are trying to do correctly, you probably want to use a DispatchGroup

    Here is an example:

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

    This will print something like:

    b
    c
    a
    // ^ in some order
    - done