0

I want to download data from my server to be displayed on a map. Therefore I use async methods to get the data. The goal is to have an array of annotation objects to be displayed.

Therefore I first download Information A and then Information B. As both are async methods, I guess I need to wait for the completionHandler to return true so I know the data is loaded. This is easy for one method. But how do I handle to wait for both methods before the completionHandler of getInformationFromServer returns true and triggers therefore the addition of annotations?

override func viewWillAppear(animated: Bool) {
    self.customizeInterface()
    self.getInformationFromServer { (completed) -> Void in
        if(completed) {
            self.mapView.addAnnotations(self.annotationArray)
        }
    }        
}

func getInformationFromServer(completionHandler: (completed: Bool) -> Void) {

    getInformationFromServerA { (downloadCompleted) -> Void in
        completionHandler(completed: downloadCompleted)
    }

// HOW DO I MANAGE TO ONLY RETURN THE COMPLETION HANDLER TRUE WHEN
// BOTH FUNCTIONS RETURNED TRUE? 

}

func getInformationFromServerA(completionHandler: (downloadCompleted: Bool) -> Void) {
    Server().getJsonInformationFromServer(url: "aeds", completionHandler: { (response) -> Void in
        self.parseAEDInformationToAnnotation(response["data"])
        completionHandler(downloadCompleted: true)
    })
}

func getInformationFromServerB(completionHandler: (downloadCompleted: Bool) -> Void) {
    Server().getJsonInformationFromServer(url: "aeds", completionHandler: { (response) -> Void in
        self.parseAEDInformationToAnnotation(response["data"])
        completionHandler(downloadCompleted: true)
    })
}

2 Answers 2

1

You may use a dispatch group to wait until both downloads finish.

func getInformationFromServer(completionHandler: (completed: Bool) -> Void) {
    let dispatchGroup = dispatch_group_create()

    var downloadCompletedA: Bool = false
    dispatch_group_enter(dispatchGroup)
    getInformationFromServerA { (downloadCompleted) -> Void in
        downloadCompletedA = downloadCompleted
        dispatch_group_leave(dispatchGroup)
    }

    var downloadCompletedB: Bool = false
    dispatch_group_enter(dispatchGroup)
    getInformationFromServerB { (downloadCompleted) -> Void in
        downloadCompletedB = downloadCompleted
        dispatch_group_leave(dispatchGroup)
    }

    // wait until both downloads are finished
    dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER)

    completionHandler(downloadCompletedA && downloadCompletedB)
}

See Apple's Concurrency Programming Guide:

Dispatch groups are a way to block a thread until one or more tasks finish executing. You can use this behavior in places where you cannot make progress until all of the specified tasks are complete.

Sign up to request clarification or add additional context in comments.

Comments

0

Another solution which I can recommend for you and it's not so "complex" as solution with dispatch_group_wait:

func getInformationFromServer(completionHandler: (completed: Bool) -> Void) {

    getInformationFromServerA { [weak self] (downloadCompleted: Bool) -> Void in
        if downloadCompleted {
            self?.getInformationFromServerB({ (downloadCompleted: Bool) -> Void in
                completionHandler(completed: downloadCompleted)
            })
        }
        else {
            completionHandler(completed: downloadCompleted)
        }
    }
}

1 Comment

I was somehow hesitant to nest the methods for accessing the server. Hm

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.