發(fā)生在Objective-C層的奔潰異常,稱為:OC Exception
1. NSException介紹
如果說你對NSException這個類不了解,那這下面這張圖的輸出內(nèi)容在開發(fā)過程中肯定經(jīng)常和你見面:

附導(dǎo)致上圖中拋出錯誤的代碼:
NSMutableArray *array = [NSMutableArray array];
NSString *strObj = nil;
[array addObject:strObj];
這樣的錯誤是致命的,也就說在不做任何容錯的情況下,程序直接Crash,也就是俗稱”閃退“,解決這類iOS提供的SDK導(dǎo)致的崩潰異常可以使用NSSetUncaughtExceptionHandler來進(jìn)行處理,附GitHub鏈接:
但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í)行過程會有以下幾種情況:
- try塊代碼沒有發(fā)生異常,則程序會執(zhí)行try塊內(nèi)、finally塊內(nèi)、finally塊之后的代碼;
- try塊代碼發(fā)生了異常,并且有catch捕捉匹配的異常,則程序在try塊內(nèi)發(fā)生異常后剩下的代碼將不再執(zhí)行,跳轉(zhuǎn)到catch塊內(nèi)并拋出NSException對象;
- 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鏈接:
如果本文對你有所幫助,記得點擊一下喜歡哈