何时使用主队列

When to use main queue

我知道 UI 的任何更新都应该在主队列中 运行 使用以下语法:

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

其他这些案例呢?

在我的 viewDidLoad() 中,我有代码来风格化导航栏和工具栏,如下所示:

    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()

我是否也应该将此代码包装在主队列中?

在我的 tableView cellForRowAtIndexPath 函数中,我是否也应该包装所有设置主队列中每个 table 单元格的 UI 的代码?

当我呈现一个新的模态控制器(self.presentViewController(modalController,animated:true,completion:nil)时,我应该将它包装在主队列中吗?

你所有问题的答案是"no"

除非文档中指定,否则所有 UIKit 函数都将在主队列上调用。

通常,在调用异步函数后,您需要在主队列上专门 运行 完成处理程序 运行 在后台队列上。像……

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

是的,只有在后台队列上已经异步执行某个函数时,您才应该调用主队列。而这往往不会自行发生。

正如 Ashley 所说,UIKit 方法会自动从主队列中调用——它们就是这样。那么按理说,有些框架有自动从后台队列调用的方法。

我知道 URLSession 的 dataTask 的 resume 函数会自动在后台队列上执行(这样应用程序就不会因网络连接而变慢),这意味着完成处理程序之后执行也适用于后台队列。这就是为什么在完成处理程序中发生的任何 UI 更新 当然需要 对主队列的调用。

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()