2

I'm trying to make background api call and update UI when it returns the result, I've check GCD documentation.
Is there a problem with logic below?

    // get data from server
    let priority = DISPATCH_QUEUE_PRIORITY_BACKGROUND
    dispatch_async(dispatch_get_global_queue(priority, 0)) {
       self.getUserData() // update self.data1 global variable
       self.getCompanyData() // update self.data2 global variable

        dispatch_async(dispatch_get_main_queue()) {
                self.updateUI() //update UI using self.data1 and self.data2 global variable
        }

    }


func getUserData(){
... api1 call
... print("1")

}

func getCompanyData(){
... api2 call
... print("2")
}

func updateUI(){
... print("UI")
}

When it executes, output is basically; UI
1
2


I would like to call updateUI function after api both of api calls are finished.


one of the api call function below;

let fullUrl = self.apiDomain + "/user_details/" + String(self.user_id)
    let url:NSURL = NSURL(string: fullUrl)!
    let session = NSURLSession.sharedSession()
    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "GET"
    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData

    let task = session.dataTaskWithRequest(request) {
        (
        let data, let response, let error) in
        guard let _:NSData = data, let _:NSURLResponse = response  where error == nil else {
            print(error)
            return
        }

            var apiCallResult: [String:AnyObject]?
            let result = NSString(data: data!, encoding: NSUTF8StringEncoding)
            do {
                apiCallResult = try NSJSONSerialization.JSONObjectWithData(result!.dataUsingEncoding(NSUTF8StringEncoding)!, options: []) as? Dictionary<String, AnyObject>
            } catch let error as NSError {
                print(error.localizedDescription)
                return
            }

            let aa = apiCallResult!["data"]! as! NSDictionary
            print(aa)

    }

    task.resume() 
5
  • updating the question. thanks. Commented Jan 6, 2016 at 14:44
  • There is no problem if both getUserData() and getCompanyData() do not work asynchronously. Commented Jan 6, 2016 at 14:44
  • Like @vadian hinted, the problem is because "getUserData" and "getCompanyData" are also asynchronous API calls. Commented Jan 6, 2016 at 14:55
  • @EricD. any advice? How can I wait both of them finish and update the UI? Commented Jan 6, 2016 at 14:59
  • I guess just like this right? self.getUserData() -> self.getCompanyData() -> self.updateUI() .... 3 of them should be in same dispatch_async Commented Jan 6, 2016 at 15:01

1 Answer 1

4

You can use dispatch groups. Here is the code example for waiting on synchronous tasks:

let group = dispatch_group_create()

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { () -> Void in
    print("Block1")
    NSThread.sleepForTimeInterval(1.0)
    print("Block1 End")
}

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { () -> Void in
    print("Block2")
    NSThread.sleepForTimeInterval(1.0)
    print("Block2 End")
}

dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { () -> Void in
    print("Block3")
}

and could produce output like this:

Block1
Block2
Block1 End
Block2 End
Block3

If you use dispatch groups to wait on multiple asynchronous tasks, you need to use dispatch_group_enter, dispatch_group_leave and dispatch_group_wait. Here is the code example.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in
    let group = dispatch_group_create()

    print("Block1")
    dispatch_group_enter(group)
    foo1.sendAsynchronousRequest() {
        print("Block1 End")
        dispatch_group_leave(group)
    }

    print("Block2")
    dispatch_group_enter(group)
    foo2.sendAsynchronousRequest() {
        print("Block1 End")
        dispatch_group_leave(group)
    }

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        print("Block3")
    })
} 

Read here for more details http://www.raywenderlich.com/79150/grand-central-dispatch-tutorial-swift-part-2

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

7 Comments

When I try with prints, it works as you mentioned. But when I call function instead of print, which calls api to get results, it prints block3 and then api call result.
I think getUserData() and getCompanyData() needs to work synchronous because dispatch_group_async already supports asynchronous.
can you explain a bit more please? Btw, thank you for "dispatch groups", it's very useful.
I think you call the functions that work asynchronous inside the dispatch_group_async for block 1 and block 2 so It immediately marks the block 1 and block 2 finished and notify to block 3.
What is foo1 and foo2?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.