web-dev-qa-db-ja.com

レイアウトエンジンへの変更は、メインスレッドからアクセスした後、バックグラウンドスレッドから実行しないでください。

既存のUIViewControllerを自動レイアウトに変換した後にこのクラッシュが発生しました。原因がわかりません。 dispatch_async(dispatch_get_global_queue(...))呼び出しを検索しましたが、レイアウトを変更するものはありません。

スタックトレースも非常に役に立ちません。

* thread #18: tid = 0x73617, 0x0000000183aa8524 libobjc.A.dylib`objc_exception_throw, stop reason = breakpoint 3.1
  * frame #0: 0x0000000183aa8524 libobjc.A.dylib`objc_exception_throw
    frame #1: 0x0000000185071100 CoreFoundation`+[NSException raise:format:] + 116
    frame #2: 0x0000000185c83894 Foundation`_AssertAutolayoutOnAllowedThreadsOnly + 192
    frame #3: 0x0000000185c835d4 Foundation`-[NSISEngine _optimizeWithoutRebuilding] + 76
    frame #4: 0x0000000185aceddc Foundation`-[NSISEngine optimize] + 112
    frame #5: 0x0000000185c82270 Foundation`-[NSISEngine performPendingChangeNotifications] + 112
    frame #6: 0x000000018af23e18 UIKit`-[UIView(Hierarchy) layoutSubviews] + 220
    frame #7: 0x000000018b15fff8 UIKit`-[UISlider layoutSubviews] + 192
    frame #8: 0x000000018af23a80 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1196
    frame #9: 0x00000001883d19d8 QuartzCore`-[CALayer layoutSublayers] + 148
    frame #10: 0x00000001883c64cc QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 292
    frame #11: 0x00000001883c638c QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32
    frame #12: 0x00000001883433e0 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 252
    frame #13: 0x000000018836aa68 QuartzCore`CA::Transaction::commit() + 512
    frame #14: 0x000000018836af34 QuartzCore`CA::Transaction::release_thread(void*) + 660
    frame #15: 0x0000000184103fbc libsystem_pthread.dylib`_pthread_tsd_cleanup + 572
    frame #16: 0x0000000184103ce4 libsystem_pthread.dylib`_pthread_exit + 200
    frame #17: 0x0000000184103378 libsystem_pthread.dylib`_pthread_wqthread + 1504
    frame #18: 0x0000000184102d8c libsystem_pthread.dylib`start_wqthread + 4
(lldb)

レイアウトをトリガーした正確な場所を把握する方法はありますか?

6
Iulian Onofrei

スタックトレースをもう一度調べたところ、ようやく問題が見つかりました。問題は、バックグラウンドスレッドでvalueインスタンスのUISliderプロパティを変更していたことでした。

しかし、メインスレッドで変更する必要があるとはどこにも述べられていません! (ありがとう、Apple)どうやら、UISlidervalueのセッターを実装し、レイアウトなどを強制しているようです。

7
Iulian Onofrei

UIでの変更は常にメインスレッドで行う必要があります。また、重要なテーマは、バックグラウンドスレッドでビューからオブジェクトを作成できることです!!!ただし、show in viewやその他の変更については、メインスレッドで機能する必要があり、この問題がこの問題が発生する主な理由です。

最後に、この問題を解決するために、「DispatchQueue」から簡単に使用できます。

DispatchQueue.main.async {
  // do your work
}
2
Saeed