gotnull
gotnull

Reputation: 27214

Can someone explain dispatch_async() for me in this scenario

I had the following method in a separate class:

class API: NSObject {

    var data = NSData()
    var delegate: APIProtocol?

    func getItems(callback: (Array<Image>) -> ()) {
        let urlPath: NSString = "http://localhost:3000/files"
        let url = NSURL(string: urlPath)

        let request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        let config = NSURLSessionConfiguration.defaultSessionConfiguration() as NSURLSessionConfiguration
        let session = NSURLSession(configuration: config) as NSURLSession

        var dataTask = NSURLSessionDataTask()
        dataTask = session.dataTaskWithRequest(request) { (data, response, error) in
            if (error == nil) {
                println("API at URL \(url)")

                let responseArray = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSArray
                var images = Image[]()
                for item: AnyObject in responseArray {
                    var location = Image(dict: item as NSDictionary)
                    images.append(location)
                }
                var img = images[0] as Image
                callback(images)

                //self.delegate?.didReceiveResponse(responseArray)
            }

        }
        dataTask.resume()
    }
}

I couldn't get my tableView to reload when calling self.tableView.reloadData() inside the callback() until I added the dispatch_async() around it.

My questions are:

1) Why wouldn't it work without it and is it the proper thing for me to do now that it's refreshing the tableView correctly?

2) Is there another way to get it working without having to add the dispatch on the main queue?

api.getItems() { (theArray) in
    dispatch_async(dispatch_get_main_queue(), {
        self.images = theArray
        self.tableView.reloadData()
        if (viaPullToRefresh) {
            self.refreshControl.endRefreshing()
        }
    })
}

Upvotes: 2

Views: 942

Answers (1)

David Arve
David Arve

Reputation: 894

When creating a NSURLSession you can specify the delegate/completion queue. If you don't specify a queue

the session creates a serial operation queue for performing all delegate method calls and completion handler calls.

So this means that your callbacks are called on a private serial queue. Now, all UI must be updated on the main queue, this is why tableView.reloadData() wasn't working.

To remove the dispatch call to the main_queue create the session like this

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

Upvotes: 6

Related Questions