##はじめに
処理実行を行う際に、AppKitやUIKitに対する操作はメインスレッドからの場合しか動作が保証されていないため、メインスレッド以外のスレッドから実行すべきではありません。
自分でスレッドを指定してコーディングをする場合は、この点を注意するのですが、コンポーネントに用意されているメソッドのcompletion handler内での処理で少々つまづいたことがあったため、今後のためのメモとして記載いたします。
##検証環境
以下の環境を使用しています。
- macOS Sierra Version 10.12.6
- Xcode Version 9.0.0 GM
- iOS11.0 GM
##UI要素への直接アクセスを避けるべきcompletion handler
以下のメソッドの場合はcompletion handlerでのUI要素への直接アクセスは避けるべきです。直接UI要素にアクセスした場合、意図しない動作やクラッシュの原因になります。
AVCaptureDevice.requestAccess(for: AVMediaType, completionHandler: { (authentication) in }
PHPhotoLibrary.requestAuthorization { (authorization) in }
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: .alert) { (authorization, error) in }
let session = URLSession.shared
let url = URL(string: "https://hogehoge.com")
session.dataTask(with: url!) { (data, response, error) in }
例えばですが、AVCaptureDevice
のrequestAccessには以下のように書かれています。使用許諾でtrueと返ってきた場合にカメラ画面に遷移する、通信結果を元にtableViewのreloadDataを行うなどやってしまいがちかと思いますので、注意が必要かと思われます。
The completion handler is called on an arbitrary dispatch queue.
Is it the client's responsibility to ensure that any
UIKit-related updates are called on the main queue or
main thread as a result.
Apple Document - requestAccess(for:completionHandler:)
##対処方法
mainスレッドで実行するように修正します。
AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (authentication) in
DispatchQueue.main.async {
let viewController = UIViewController()
navigationController.pushViewController(viewController, animated: true)
}
}
##その他(Main thread checkerについて)
Xcode9からmain thread checkerが登場し、不正なスレッドでのAppKit, UIKitなどへのアクセスを検知するようになったようです。
Main Thread Checker