JK140
JK140

Reputation: 785

When to use main queue

I know any updates to UI should be run inside the main queue using the below syntax:

dispatch_async(dispatch_get_main_queue()) {
   UI update code here
}

What about these other cases?

In my viewDidLoad(), I have code to stylize the navbar and toolbar, like below:

    let nav = self.navigationController?.navigationBar
    nav?.barStyle = UIBarStyle.Default
    nav?.tintColor = UIColor.blackColor()
    nav?.barTintColor = UIColor(red:133.0/255, green:182.0/255, blue:189.0/255, alpha:1.0)

    let toolBar = self.navigationController?.toolbar
    toolBar?.barTintColor = UIColor(red:231/255, green:111/255, blue:19.0/255, alpha:1.0)
    toolBar?.tintColor = UIColor.blackColor()

Should I wrap this code inside the main queue as well?

In my tableView cellForRowAtIndexPath function, should I wrap all the code setting up the UI of each table cell in the main queue as well?

When I present a new modal controller (self.presentViewController(modalController, animated: true, completion: nil), should I wrap this inside the main queue?

Upvotes: 2

Views: 1492

Answers (2)

Terry Torres
Terry Torres

Reputation: 138

Yeah, calling the main queue is something you should only have to do if a function was already being performed asynchronously on a background queue. And that doesn't tend to happen by itself.

Like Ashley says, UIKit methods are automatically called from the main queue – that's just how they are. It stands to reason, then, that some frameworks have methods that automatically call from a background queue.

I know that URLSession's dataTask's resume function automatically executes on a background queue (so that the app isn't slowed down by a web connection), which means the completion handler that executes afterward ALSO works on a background queue. That's why any UI updates that happen in the completion handler certainly require a call on the main queue.

let dataTask = URLSession.shared.dataTask(with: request) {
    // begin completion handler
    (data, response, error) in
    guard error == nil else { print("error \(error.debugDescription)"); return }
    guard let data = data else { print("no data"); return }
    do {
        if let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: Any]] {
            print("sending returned JSON to handler")
            self.responseHandler.handleAPIResponse(jsonArray: json)
       >>>> DispatchQueue.main.async { <<<<
                self.tableView.reloadData()
            }
        }
    } catch {
        print("get tasks JSONSerialization error")
    }
}
dataTask.resume()

Upvotes: 2

Ashley Mills
Ashley Mills

Reputation: 53082

The answer to all your questions is "no"

Unless specified in the documentation, all UIKit functions will be called on the main queue.

Generally, you'll need to specifically run on the main queue after calling an async func with a completion handler that runs on a background queue. Something like…

// downloadImage is some func where the 
// completion handler runs on a background queue
downloadImage(completion: { image in  
    DispatchQueue.main.async {
        self.imageView.image = image
    }
})

Upvotes: 8

Related Questions