swiftasynchronousgrand-central-dispatchnsoperation

Wait until swift for loop with asynchronous network requests finishes executing


I would like a for in loop to send off a bunch of network requests to firebase, then pass the data to a new view controller once the the method finishes executing. Here is my code:

var datesArray = [String: AnyObject]()

for key in locationsArray {       
    let ref = Firebase(url: "http://myfirebase.com/" + "\(key.0)")
    ref.observeSingleEventOfType(.Value, withBlock: { snapshot in

        datesArray["\(key.0)"] = snapshot.value
    })
}
// Segue to new view controller here and pass datesArray once it is complete 

I have a couple concerns. First, how do I wait until the for loop is finished and all the network requests are complete? I can't modify the observeSingleEventOfType function, it is part of the firebase SDK. Also, will I create some sort of race condition by trying to access the datesArray from different iterations of the for loop (hope that makes sense)? I've been reading about GCD and NSOperation but I'm a bit lost as this is the first app I've built.

Note: Locations array is an array containing the keys I need to access in firebase. Also, it's important that the network requests are fired off asynchronously. I just want to wait until ALL the asynchronous requests complete before I pass the datesArray to the next view controller.


Solution

  • You can use dispatch groups to fire an asynchronous callback when all your requests finish.

    Here's an example using dispatch groups to execute a callback asynchronously when multiple networking requests have all finished.

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let myGroup = DispatchGroup()
    
        for i in 0 ..< 5 {
            myGroup.enter()
    
            Alamofire.request("https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
                print("Finished request \(i)")
                myGroup.leave()
            }
        }
    
        myGroup.notify(queue: .main) {
            print("Finished all requests.")
        }
    }
    

    Output

    Finished request 1
    Finished request 0
    Finished request 2
    Finished request 3
    Finished request 4
    Finished all requests.