iOS 發(fā)生在Objective-C層(OC Exception)的異常

發(fā)生在Objective-C層的奔潰異常,稱為:OC Exception

1. NSException介紹

如果說你對NSException這個類不了解,那這下面這張圖的輸出內(nèi)容在開發(fā)過程中肯定經(jīng)常和你見面:

圖片.png

附導(dǎo)致上圖中拋出錯誤的代碼:

NSMutableArray *array = [NSMutableArray array];
NSString *strObj = nil;
[array addObject:strObj];

這樣的錯誤是致命的,也就說在不做任何容錯的情況下,程序直接Crash,也就是俗稱”閃退“,解決這類iOS提供的SDK導(dǎo)致的崩潰異常可以使用NSSetUncaughtExceptionHandler來進(jìn)行處理,附GitHub鏈接:

https://github.com/minibear0523/UncaughtExceptionHandler

但App奔潰的的原因還有內(nèi)存訪問錯誤、重復(fù)釋放等問題,這些異常NSSetUncaughtExceptionHandler是無法處理的,因為這類錯誤發(fā)送的是SIGNAL。

2. NSException處理

蘋果提供了NSError錯誤處理和NSException異常處理兩種機(jī)制,NSError用來處理程序中可恢復(fù)的錯誤(通常情況下程序可以繼續(xù)運行),而NSException用來處理不可恢復(fù)的錯誤(會導(dǎo)致程序終止的嚴(yán)重異常)

在沒有研究NSException之前,蘋果開發(fā)一直有個令我非常疑惑的地方,就是Java中經(jīng)常使用的try{****} catch{****},為什么在iOS代碼中幾乎見不到?這個得益于ARC自動內(nèi)存管理,在大多數(shù)時候開發(fā)者并不需要手動管理內(nèi)存(并不是絕對安全),但是如果你面對某段有潛在奔潰風(fēng)險的代碼,則可以使用try catch來捕捉異常:

@try {
    //放有可能會出現(xiàn)異常錯誤的代碼
}
@catch (NSException *exception) {
    //只有try塊中的代碼出現(xiàn)了異常才會執(zhí)行,用于匹配處理拋出的異常
}
@finally {
    //無論是否拋出異常,都會執(zhí)行的代碼
}

整個執(zhí)行過程會有以下幾種情況:

  1. try塊代碼沒有發(fā)生異常,則程序會執(zhí)行try塊內(nèi)、finally塊內(nèi)、finally塊之后的代碼;
  2. try塊代碼發(fā)生了異常,并且有catch捕捉匹配的異常,則程序在try塊內(nèi)發(fā)生異常后剩下的代碼將不再執(zhí)行,跳轉(zhuǎn)到catch塊內(nèi)并拋出NSException對象;
  3. try塊代碼發(fā)生了異常,并且有catch沒有能匹配捕捉,則程序會執(zhí)行try和finally塊中的代碼,并將異常返回給調(diào)用者,finally塊之后的代碼也不執(zhí)行。

通過try catch方法可以解決很多問題,上面addObject插入nil對象的奔潰也可以被妥善解決:

    @try {
        [array addObject:strObj];
    }
    @catch (NSException *exception) {
        //打印exception輸出:
        //exception.name = NSInvalidArgumentException
        //exception.reason = *** -[NSArrayM insertObject:atIndex:]: object cannot be nil
        //還可以通過exception.callStackSymbols查看函數(shù)堆棧,發(fā)現(xiàn)對應(yīng)異常錯誤發(fā)生在哪個類中的哪一行
    }
    @finally {
        
    }

3. Foundation常見奔潰異常

Foundation是我們在開發(fā)過程中最常使用的框架,與CoreFoundation不同F(xiàn)oundation提供的是Objective-C接口,他主要提供了:數(shù)據(jù)類型(數(shù)組、字典、集合等)、字符串、時間、日期、URL、線程、RunLoop等。

這也造成了很多異常的發(fā)送,比如:

  • 數(shù)組越界
  • 可變數(shù)組插入空對象
  • KVO在addObserver后不remove
  • 調(diào)用對象方法找不到selector對應(yīng)的函數(shù)時,消息轉(zhuǎn)發(fā)

可以利用Runtime特性在Category使用新函數(shù)替換掉系統(tǒng)的存在異常風(fēng)險的方法

4. 在發(fā)布到App Store的版本中,通過上述手段捕捉的異常如何得知?

由于我們將異常捕獲了,所以程序不會產(chǎn)生奔潰現(xiàn)象,那么在這樣的情況下作為開發(fā)者如何收集這些被捕獲的異常呢?顯然像友盟、Bugly這樣的第三方SDK根本不管用了,其實完全可以自給自足,我是通過騰訊Mars框架中的Xlog來實現(xiàn)的,并且人家的框架生成的.xlog文件還支持非對稱加密,保證了在網(wǎng)絡(luò)傳輸過程中即使被截獲也不用擔(dān)心泄漏。
附上Mars的GitHub鏈接:

https://github.com/Tencent/mars

如果本文對你有所幫助,記得點擊一下喜歡哈

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容