tiamat
tiamat

Reputation: 961

swift asynchronous request using dispatch_group_notify doesn't work

I'm trying to use dispatch_group_notify to send a HTTP request where I need to wait for the result of this command before continuing my processing.

here is the following call:

self.save(){(response) in
    if let result = response as? Bool {
        if(result == true){
            dispatch_group_notify(self.myGroup!, dispatch_get_main_queue(), {
                print("send carnet finished")
                let registrationView = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("carnetTable") as! CarnetTableViewController
                self.navigationController?.pushViewController(registrationView, animated: true)
            })

        }

        }
    }

and here is the function who is sending the HTTP command:

    func save(callback: (AnyObject) -> ()){
    dispatch_group_enter(self.myGroup)

    let p = pickerDataSource[patients.selectedRowInComponent(0)]

    let params = "owner=\(User.sharedInstance.email)&patient=\(p)&carnet=\(commentaires.text!)"

    let final_url = url_to_request + "?" + params.stringByAddingPercentEncodingForISOLatin1()!
    print("URL addCarnet: \(final_url)")

    let url:NSURL = NSURL(string: final_url)!

    //let session = NSURLSession.sharedSession()
    let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: configuration,
                               delegate: self,
                               delegateQueue:NSOperationQueue.mainQueue())

    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "GET"
    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
    request.timeoutInterval = 10


    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 data")
            dispatch_group_leave(self.myGroup)
            callback(false)
            return
        }
        var result = NSString(data: data!, encoding:NSASCIIStringEncoding)!
        print("result: \(result)")
    }

    task.resume()
    dispatch_group_leave(self.myGroup)
    callback(true)

}

I would like to ensure that save function is finished (dispatch_group_leave) before opening the new ViewController (CarnetTableViewController) but I can see that ViewController is called before the end of the dispatch_group...

how can I ensure the end of the save function before opening the new View ?

Upvotes: 0

Views: 221

Answers (1)

Rob Napier
Rob Napier

Reputation: 299275

The last three lines of your function:

task.resume()
dispatch_group_leave(self.myGroup)
callback(true)

This causes the task to start, and then you immediately (before the task has completed), leave the group and call the callback.

If you trace through the code, your dispatch_group_enter and dispatch_group_leave occur in the same scope, on the same queue, and before you call callback(). That means they're not actually doing anything. By the time you get to your callback, the dispatch_group is empty.

If you had an error, I'd expect a problem when that error-leg calls dispatch_group_leave a second time (since this is unbalanced).

You meant this:

    ...
    var result = NSString(data: data!, encoding:NSASCIIStringEncoding)!
    print("result: \(result)")
    dispatch_group_leave(self.myGroup)
    callback(true)
}

task.resume()

Upvotes: 1

Related Questions