以下是Firebase的崩溃日志:
Fatal Exception: NSInternalInconsistencyException
Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.`
0 应用名称 0x100df14e4 CLSProcessRecordAllThreads + 4316009700
1 应用名称 0x100df18cc CLSProcessRecordAllThreads + 4316010700
2 应用名称 0x100de1144 CLSHandler + 4315943236
3 应用名称 0x100defae8 __CLSExceptionRecord_block_invoke + 4316003048
4 libdispatch.dylib 0x1c515c184 _dispatch_client_callout + 16
5 libdispatch.dylib 0x1c510ec44 _dispatch_lane_barrier_sync_invoke_and_complete + 56
6 应用名称 0x100def554 CLSExceptionRecord + 4316001620
7 应用名称 0x100def380 CLSExceptionRecordNSException + 4316001152
8 应用名称 0x100deef74 CLSTerminateHandler() + 4316000116
9 libc++abi.dylib 0x1c525c304 std::__terminate(void (*)()) + 16
10 libc++abi.dylib 0x1c525bc58 __cxa_get_exception_ptr + 30
11 libc++abi.dylib 0x1c525bc18 __cxxabiv1::exception_cleanup_func(_Unwind_Reason_Code, _Unwind_Exception*) + 122
12 libobjc.A.dylib 0x1c51b71d0 _objc_exception_destructor(void*) + 354
13 Foundation 0x1c5964d64 -[NSISEngine tryToOptimizeReturningMutuallyExclusiveConstraints] + 318
14 Foundation 0x1c57662dc -[NSISEngine withBehaviors:performModifications:] + 32
15 UIKitCore 0x1c984fee4 -[UIView(UIConstraintBasedLayout) _resetLayoutEngineHostConstraints] + 76
16 UIKitCore 0x1c99271b4 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1952
17 QuartzCore 0x1cbe135f8 -[CALayer layoutSublayers] + 284
18 QuartzCore 0x1cbe17e28 CA::Layer::layout_if_needed(CA::Transaction*) + 480
19 QuartzCore 0x1cbe23894 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 136
20 QuartzCore 0x1cbd6c9f0 CA::Context::commit_transaction(CA::Transaction*, double) + 304
21 QuartzCore 0x1cbd96890 CA::Transaction::commit() + 676
22 QuartzCore 0x1cbd97814 CA::Transaction::release_thread(void*) + 228
23 libsystem_pthread.dylib 0x1c51ae350 _pthread_tsd_cleanup + 580
24 libsystem_pthread.dylib 0x1c51ab248 _pthread_exit + 80
25 libsystem_pthread.dylib 0x1c51ac29c _pthread_wqthread_legacy_worker_wrap + 94
26 libsystem_pthread.dylib 0x1c51ac034 _pthread_wqthread + 420
27 libsystem_pthread.dylib 0x1c51aeae0 start_wqthread + 8
错误信息:Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread
翻译成中文的意思大概就是:绝对不能改变布局在后台线程中,必须在主线程中才能进行布局操作
大家都知道在iOS开发中,UI操作都必须放在主线程中进行,如果在后台线程更新UI会导致一些不可预知的错误。在实际开发中,难免会把一些UI操作放在了后台线程中,比如网络请求回来后处理等等,在iOS 13之前的系统中貌似并不会导致崩溃,知识控制台有log警告,但在iOS 13中某些操作就会导致文章开头的崩溃。这堆栈信息让人无从下手。
我把我自己解决问题的方式放在这里跟大家做个分享:
- 网络请求回调在子线程中更新UI:
这个如果是基于AFNetWorking基本都不会出现问题,因为AFNetWorking会把回调结果抛回到主线程,如果是自己实现的NSURLSession那么就要注意了,一定要把更新UI的操作抛回主线程,比如tableView,collectionView 的reloadData,按钮的隐藏等等。 - 项目中用到第三方库需要注意
第三方库的代理回调上层时要注意是主线程还是后台线程,特别是需要根据回调来改变UI的时候。一定要确保是在主线程。我遇到的问题就是第三方回调是后台线程,结果在里面进行了collectionView的reloadData操作导致应用crash掉。 - 自己在把UI更新的代码写在了后台线程中。
- 一些系统的UI方法,比如进行网络请求时让状态栏显示小菊花动画[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES],就应该放到主线程中进行。我们项目里ASIHTTPRequest就是在后台线程中调用了setNetworkActivityIndicatorVisible方法。AFNetWorking则不存在这个问题。
总结:一定要避免在后台线程中更新UI,遇到后台线程就要考虑是否需要更新界面UI,如果需要就要抛回主线程里。
来源:oschina
链接:https://my.oschina.net/jack088/blog/4743310