1.NSInvalidArgumentException 異常
出現(xiàn)這種異常的原因一般是在不可以出現(xiàn)nil數(shù)據(jù)的時候傳入了nil,比如在創(chuàng)建NSDictionary的時候值傳入了nil就會出現(xiàn)這種崩潰錯誤,如果必須傳空需要把nil對象轉(zhuǎn)成NSNull才可以確保不出現(xiàn)這種錯誤,有3種方案可以解決該問題,如下:
方案一:后臺在返回數(shù)據(jù)的時候進行校驗,對空值進行處理。但是在項目中有些空值是有特殊的用途,此種方案不可行。
方案二:在轉(zhuǎn)換成NSDictionary的時候,對后臺返回的數(shù)據(jù)進行校驗,把空值轉(zhuǎn)換成NSNull對象。方案可行,但是需要對現(xiàn)有代碼做大的改動,每次轉(zhuǎn)換的時候都需要進行校驗,太麻煩。業(yè)務(wù)高速發(fā)展時期,這樣做成本太高。
方案三:有沒有一種無須改動現(xiàn)有代碼又能解決該問題呢?答案是有的,可以利用Objective-C的runtime來解決該問題。
NSDictionary插入nil對象會造成崩潰,但是插入NSNull對象是不會造成崩潰的,只要利用runtime的Swizzle Method把nil對象給轉(zhuǎn)換成NSNull對象就可以把該問題給解決了。創(chuàng)建一個NSDictionary的類別,利用runtime的Swizzle Method來替換系統(tǒng)的方法。源碼實現(xiàn)可以參考Glow團隊封裝的NSDictionary+NilSafe(Github上可下載到), 現(xiàn)截取其中的部分代碼如下:
+ (instancetype)gl_dictionaryWithObjects:(const id [])objects forKeys:(const id<NSCopying> [])keys count:(NSUInteger)cnt {
id safeObjects[cnt];
id safeKeys[cnt];
NSUInteger j = 0;
for (NSUInteger i = 0; i < cnt; i++) {
id key = keys[i];
id obj = objects[i];
if (!key) {
continue;
}
if (!obj) {
obj = [NSNull null];
}
safeKeys[j] = key;
safeObjects[j] = obj;
j++;
}
return [self gl_dictionaryWithObjects:safeObjects forKeys:safeKeys count:j];
}
2.data parameter is nil
NSJSONSerialization序列化的時候,傳入data為nil,造成的崩潰,這個問題比較好解決,在序列化的時候,統(tǒng)一加入判斷,判斷data是不是nil即可。
3.unrecognized selector sent to instance 0x15d23910
造成這條崩潰的原因,想必大家都比較熟悉了,就是一個類調(diào)用了一個不存在的方法,造成的崩潰。解決這樣的問題,可以在寫一個方法的時候,判斷一下其類的類型,不符合類型的不讓其調(diào)用
4.SIGSEGV 異常
當去訪問沒有被開辟的內(nèi)存或者已經(jīng)被釋放的內(nèi)存時,就會發(fā)生這樣的異常。另外,在低內(nèi)存的時候,也可能會產(chǎn)生這樣的異常,一般開發(fā)中用到C語言呢的時候比較容易出現(xiàn)這種錯誤,因為ARC并不會對C語言進行內(nèi)存管理,所以用C語言創(chuàng)建的對象一定要手動Free
5.Can't add self as subview crash
造成這個崩潰的原因,一種原因是在push或pop一個視圖的時候,并且設(shè)置了animated:YES,如果此時動畫(animated)還沒有完成,這個時候,你在去push或pop另外一個視圖的時候,就會造成該異常。
解決該異常最簡單的方式是把animated設(shè)置為NO,但是很不友好,把系統(tǒng)自帶的動畫效果給去掉了。另外一種友好的方式就是通過runtime來進行實現(xiàn)了,通過安全的方式,確保當有控制器正在進行入棧或出棧時,沒有其他入棧或出棧操作
6.NSRangeException 異常
越界異常,一般就是數(shù)組越界或者字符串截取越界
7.SIGPIPE 異常
先解釋一下什么是SIGPIPE異常,通俗一點的描述是這樣的:對一個端已經(jīng)關(guān)閉的socket調(diào)用兩次write,第二次write將會產(chǎn)生SIGPIPE信號,該信號默認結(jié)束進程。
那如何解決該問題呢?對SIGPIPE信號可以進行捕獲,也可將其忽略,對于iOS系統(tǒng)來說,只需要把下面這段代碼放在.pch文件中即可。
// 僅在 IOS 系統(tǒng)上支持 SO_NOSIGPIPE
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
// We do not want SIGPIPE if writing to socket.
const int value = 1;
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(int));
#endif
8.SIGABRT 異常
這是一個讓程序終止的標識,會在斷言、app內(nèi)部、操作系統(tǒng)用終止方法拋出。通常發(fā)生在異步執(zhí)行系統(tǒng)方法的時候。如CoreData、NSUserDefaults等,還有一些其他的系統(tǒng)多線程操作。
注意:這并不一定意味著是系統(tǒng)代碼存在bug,代碼僅僅是成了無效狀態(tài),或者異常狀態(tài)。