iOS13下 'threading violation: expected the main thread' Crash分析及解決

問題描述
iOS13及以上的系統(tǒng)挪捕,使用Xcode11.2編譯器運行级零,在特定的路徑下喚起系統(tǒng)拍照/錄像會直接Crash滞乙,使用該Demo的Crash的日志如下:


2019-12-24 10:28:40.709607+0800 HDCameraCrashDemo[3338:1286515] *** Assertion failure in -[FBSSerialQueue assertOnQueue], /BuildRoot/Library/Caches/com.apple.xbs/Sources/FrontBoardServices/FrontBoard-626.4.1/FrontBoardServices/FBSSerialQueue.m:98

2019-12-24 10:28:40.709836+0800 HDCameraCrashDemo[3338:1286515] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'threading violation: expected the main thread'

*** First throw call stack:

(0x1beebc96c 0x1bebd5028 0x1bedb94fc 0x1bf1fa700 0x1c40eb7ec 0x1c409d460 0x1c409d6ec 0x1c409d5e4 0x1c2b1f120 0x1c2c0ed50 0x1c2c0fb20 0x1e13c3514 0x1bebef3f8 0x1e1466118 0x1bebd4130 0x1bebe6f80 0x1bebede44 0x1e145b2c4 0x1bebef3f8 0x1bee0243c 0x1bed8cfc0 0x1bebef3f8 0x1e14be704 0x1bebd4130 0x1bebe6f80 0x1bebede44 0x1e14af8ac 0x1bebef3f8 0x1beadfa08 0x1bebef3f8 0x1beadfa08 0x1004ef27c 0x1004f690c 0x1004f74fc 0x1005024dc 0x1bebc76d0 0x1bebcd9e8)

libc++abi.dylib: terminating with uncaught exception of type NSException

(lldb) bt

* thread #4, queue = 'com.apple.camera.capture-engine.session-queue', stop reason = signal SIGABRT

  * frame #0: 0x00000001beca6efc libsystem_kernel.dylib`__pthread_kill + 8

    frame #1: 0x00000001bebc68b8 libsystem_pthread.dylib`pthread_kill + 228

    frame #2: 0x00000001beb56a74 libsystem_c.dylib`abort + 104

    frame #3: 0x00000001bec6e3c8 libc++abi.dylib`abort_message + 132

    frame #4: 0x00000001bec6e5c0 libc++abi.dylib`demangling_terminate_handler() + 308

    frame #5: 0x00000001bebd5308 libobjc.A.dylib`_objc_terminate() + 124

    frame #6: 0x00000001bec7b634 libc++abi.dylib`std::__terminate(void (*)()) + 20

    frame #7: 0x00000001bec7b5c0 libc++abi.dylib`std::terminate() + 44

    frame #8: 0x00000001bebd528c libobjc.A.dylib`objc_terminate + 16

    frame #9: 0x00000001004ef290 libdispatch.dylib`_dispatch_client_callout + 40

    frame #10: 0x00000001004f690c libdispatch.dylib`_dispatch_lane_serial_drain + 720

    frame #11: 0x00000001004f74fc libdispatch.dylib`_dispatch_lane_invoke + 408

    frame #12: 0x00000001005024dc libdispatch.dylib`_dispatch_workloop_worker_thread + 1344

    frame #13: 0x00000001bebc76d0 libsystem_pthread.dylib`_pthread_wqthread + 280

(lldb)

在實際項目中的Crash日志及堆棧信息如下:


* thread #67, queue = 'com.apple.camera.capture-engine.session-queue', stop reason = breakpoint 3.1

    frame #0: 0x00000001bebd4fec libobjc.A.dylib`objc_exception_throw

    frame #1: 0x00000001bedb94fc CoreFoundation`+[NSException raise:format:arguments:] + 100

    frame #2: 0x00000001bf1fa700 Foundation`-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 132

    frame #3: 0x00000001c40eb7ec FrontBoardServices`-[FBSSerialQueue assertOnQueue] + 236

    frame #4: 0x00000001c409d460 FrontBoardServices`-[FBSSceneImpl updateClientSettings:withTransitionContext:] + 80

    frame #5: 0x00000001c409d6ec FrontBoardServices`-[FBSSceneImpl updateClientSettingsWithTransitionBlock:] + 168

    frame #6: 0x00000001c409d5e4 FrontBoardServices`-[FBSSceneImpl updateClientSettingsWithBlock:] + 128

    frame #7: 0x00000001c2b1f120 UIKitCore`-[FBSScene(UIApp) updateUIClientSettingsWithBlock:] + 184

    frame #8: 0x00000001c2c0ed50 UIKitCore`-[UIDevice(Private) _enableDeviceOrientationEvents:] + 156

  * frame #9: 0x00000001c2c0fb20 UIKitCore`-[UIDevice endGeneratingDeviceOrientationNotifications] + 60

    frame #10: 0x00000001e13c3514 CameraUI`-[CAMMotionController dealloc] + 68

    frame #11: 0x00000001bebef3f8 libobjc.A.dylib`objc_release + 136

    frame #12: 0x00000001e1466118 CameraUI`-[CUCaptureController .cxx_destruct] + 92

    frame #13: 0x00000001bebd4130 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 116

    frame #14: 0x00000001bebe6f80 libobjc.A.dylib`objc_destructInstance + 92

    frame #15: 0x00000001bebede44 libobjc.A.dylib`_objc_rootDealloc + 52

    frame #16: 0x00000001e145b2c4 CameraUI`-[CUCaptureController dealloc] + 120

    frame #17: 0x00000001bebef3f8 libobjc.A.dylib`objc_release + 136

    frame #18: 0x00000001bee0243c CoreFoundation`__RELEASE_OBJECTS_IN_THE_ARRAY__ + 116

    frame #19: 0x00000001bed8cfc0 CoreFoundation`-[__NSArrayM dealloc] + 172

    frame #20: 0x00000001bebef3f8 libobjc.A.dylib`objc_release + 136

    frame #21: 0x00000001e14be704 CameraUI`-[CAMCaptureEngine .cxx_destruct] + 176

    frame #22: 0x00000001bebd4130 libobjc.A.dylib`object_cxxDestructFromClass(objc_object*, objc_class*) + 116

    frame #23: 0x00000001bebe6f80 libobjc.A.dylib`objc_destructInstance + 92

    frame #24: 0x00000001bebede44 libobjc.A.dylib`_objc_rootDealloc + 52

    frame #25: 0x00000001e14af8ac CameraUI`-[CAMCaptureEngine dealloc] + 168

    frame #26: 0x00000001bebef3f8 libobjc.A.dylib`objc_release + 136

    frame #27: 0x00000001beadfa08 libsystem_blocks.dylib`_Block_release + 168

    frame #28: 0x00000001bebef3f8 libobjc.A.dylib`objc_release + 136

    frame #29: 0x00000001beadfa08 libsystem_blocks.dylib`_Block_release + 168

    frame #30: 0x00000001088ff27c libdispatch.dylib`_dispatch_client_callout + 20

    frame #31: 0x000000010890690c libdispatch.dylib`_dispatch_lane_serial_drain + 720

    frame #32: 0x00000001089074fc libdispatch.dylib`_dispatch_lane_invoke + 408

    frame #33: 0x00000001089124dc libdispatch.dylib`_dispatch_workloop_worker_thread + 1344

    frame #34: 0x00000001bebc76d0 libsystem_pthread.dylib`_pthread_wqthread + 280

<video src="./HDCameraCrashDemo.mp4" controls="true" />

問題分析

在iOS13中咏闪,系統(tǒng)對在子線程進(jìn)行UI操作做了更加嚴(yán)格的檢驗匿值,會直接拋出 threading violation: expected the main thread 朴摊。該問題在真實項目中,我們對堆棧信息中的 [UIDevice endGeneratingDeviceOrientationNotifications] 進(jìn)行 hook 處理口锭,通過 Crash必現(xiàn)的路徑介杆,看到這個方法會發(fā)生在子線程中:


@implementation UIDevice (PG)

static inline void pg_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {

    Method originalMethod = class_getInstanceMethod(theClass, originalSelector);

    Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);

    method_exchangeImplementations(originalMethod, swizzledMethod);

}

+ (void)load {

    if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {

        pg_swizzleSelector(UIDevice.class, @selector(endGeneratingDeviceOrientationNotifications), @selector(pgEndGeneratingDeviceOrientationNotifications));

    }

}

- (void)pgEndGeneratingDeviceOrientationNotifications {

    NSLog(@"pgEndGeneratingDeviceOrientationNotifications isMainThread:%d", [NSThread isMainThread]);

    [self pgEndGeneratingDeviceOrientationNotifications];

}

@end



pgEndGeneratingDeviceOrientationNotifications isMainThread:0

也就是說在子線程中春哨,觸發(fā)了該方法,然后系統(tǒng)監(jiān)聽該通知做了UI操作椰拒,然后導(dǎo)致的Crash

問題解決

hook [UIDevice endGeneratingDeviceOrientationNotifications] 判斷執(zhí)行該方法是否在主線程中執(zhí)行凰荚,如果不是,則同步到主線程中轉(zhuǎn)發(fā): (最終代碼)


@implementation UIDevice (PG)

static inline void pg_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {

    Method originalMethod = class_getInstanceMethod(theClass, originalSelector);

    Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);

    method_exchangeImplementations(originalMethod, swizzledMethod);

}

+ (void)load {

    if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {

        pg_swizzleSelector(UIDevice.class, @selector(endGeneratingDeviceOrientationNotifications), @selector(pgEndGeneratingDeviceOrientationNotifications));

    }

}

- (void)pgEndGeneratingDeviceOrientationNotifications {
    NSLog(@"pgEndGeneratingDeviceOrientationNotifications isMainThread:%d", [NSThread isMainThread]);
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self pgEndGeneratingDeviceOrientationNotifications];
        });
        return;
    }
    [self pgEndGeneratingDeviceOrientationNotifications];
}

@end

問題結(jié)束了?

上面的問題解決到涂,其實的確是能解決問題,但是并沒有從根源上發(fā)現(xiàn)到底是什么地方導(dǎo)致浇雹,通過查看代碼發(fā)現(xiàn)屿讽,我們的項目中對 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications][[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications] 沒有成對實現(xiàn)聂儒,測試發(fā)現(xiàn),如果 多調(diào)用了兩次 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications] , 然后再喚起H5的拍照/錄視頻窜护,在iOS13系統(tǒng)上必然Crash非春,可以在下載 HDCameraCrashDemo 進(jìn)行驗證

可以在 [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications] 缓屠、[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications] 添加一個 BOOL 類型的變量來控制他們的成對出現(xiàn),從根本上解決這類問題滨溉。

所以這個并不一定是iOS13系統(tǒng)的問題,只要在調(diào)用系統(tǒng)方法合理得哆,并不會有該類型的Crash發(fā)生栋操。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市场勤,隨后出現(xiàn)的幾起案子和媳,更是在濱河造成了極大的恐慌留瞳,老刑警劉巖她倘,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異阶剑,居然都是意外死亡牧愁,警方通過查閱死者的電腦和手機(jī)猪半,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淋昭,“玉大人翔忽,你說我怎么就攤上這事驶悟。” “怎么了龙巨?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铭若。 經(jīng)常有香客問我,道長绞铃,這世上最難降的妖魔是什么冷离? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮揪阿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘溺健。我一直安慰自己,他們只是感情好魏颓,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著偷遗,像睡著了一般矗烛。 火紅的嫁衣襯著肌膚如雪瞭吃。 梳的紋絲不亂的頭發(fā)上歪架,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天烹棉,我揣著相機(jī)與錄音浆洗,去河邊找鬼伏社。 笑死塔淤,一個胖子當(dāng)著我的面吹牛高蜂,可吹牛的內(nèi)容都是我干的妨马。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼脖咐!你這毒婦竟也來了偿凭?” 一聲冷哼從身側(cè)響起弯囊,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤胶果,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后霎烙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡游昼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年酱床,在試婚紗的時候發(fā)現(xiàn)自己被綠了扇谣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡罐寨,死狀恐怖鸯绿,靈堂內(nèi)的尸體忽然破棺而出簸淀,到底是詐尸還是另有隱情租幕,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布男窟,位于F島的核電站贾富,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏颤枪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一扇住、第九天 我趴在偏房一處隱蔽的房頂上張望台囱。 院中可真熱鬧淡溯,春花似錦、人聲如沸米间。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至夫晌,卻和暖如春昧诱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凶掰。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工蜈亩, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畅涂。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓药有,卻偏偏與公主長得像,于是被迫代替她去往敵國和親苇经。 傳聞我的和親對象是個殘疾皇子宦言,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,089評論 1 32
  • Swift Packages 目前Pod跟SPM的兼容還沒做好蜘澜,配置好SPM后,Pod不能進(jìn)行正常更新鄙信,先配置好P...
    MMOTE閱讀 1,048評論 0 2
  • 首先手機(jī)系統(tǒng)升級為iOS13装诡,相應(yīng)的xcode的版本要升級為11 注意: 使用xcode 10 編譯的APP 在i...
    若水water閱讀 4,794評論 2 16
  • 轉(zhuǎn)摘自微信讀書 在實現(xiàn)需求的同時,能寫出既優(yōu)雅性能又高效的代碼是每個開發(fā)者都在追求的目標(biāo)宾巍,但是在實際開發(fā)中渔伯,隨著每...
    Arthurcsh閱讀 826評論 0 1
  • 古人常云:“一張一弛,文武之道”鲜侥,在學(xué)習(xí)英語的過程中诸典,穿插一下簡筆畫的學(xué)習(xí)會有助于這兩項技能的雙提升! 昨天狐粱,同事...
    剛剛的鋼閱讀 637評論 0 0