引文
之前開發(fā)中了解到Android遇到Crash觉既,可以利用框架回退到上一個頁面而不是閃退掉惧盹,然后在思考如何降低iOS的Crash率,當然最主要方法是從根源抓起瞪讼,注意代碼邏輯完成性钧椰,代碼規(guī)范性,多測試符欠。
后來知道可以通過Runtime的方法交換替換一些方法嫡霞,那么此時就可以替換掉NSArray、NSDictionary的一些插入方法希柿,進行判斷避免插入空值诊沪。
通過本文你可以學(xué)到什么?
- 簡單的方法交換和消息轉(zhuǎn)發(fā)降低crash率
- 遇到crash怎么快速定位與解決
1. 簡單的方法交換和消息轉(zhuǎn)發(fā)降低crash率
先說一些一眼能定位的異常曾撤,數(shù)組越界端姚、插入空值等,我們可以使用分類進行交換系統(tǒng)方法避免Crash挤悉,原理很簡單渐裸,見代碼:
@implementation NSArray (XQAdd)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[objc_getClass("__NSArrayI") swizzleInstanceMethod:@selector(objectAtIndex:) with:@selector(xq_objectAtIndex:)];
// [@"1"]
}
- (id)xq_objectAtIndex:(NSInteger)index {
if (index >= self.count || index < 0 || !self.count) {
return nil;
}
return [self xq_objectAtIndex:index];
}
同樣,我們也可以交換NSMutableArray的插入方法,NSDictionary的插入方法等昏鹃,可以看我寫的一個代碼示例
還有在我們獲取到網(wǎng)絡(luò)數(shù)據(jù)的時候尚氛,如果直接當字典取值,并不知道某個key存儲的值是NSNumber還是NSString洞渤,但是我的習(xí)慣性是傳值大部分使用NSString來進行怠褐,所以遇到NSNumber當NSString使用可能會發(fā)生崩潰,那么我們利用消息轉(zhuǎn)發(fā)-forwardingTargetForSelector:
來實現(xiàn)NSNumber直接當做NSString使用不崩潰您宪。主要代碼如下
@implementation NSNumber (avoidCrash)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleInstanceMethod:@selector(respondsToSelector:) with:@selector(swizzle_respondsToSelector:)];
[self swizzleInstanceMethod:@selector(forwardingTargetForSelector:) with:@selector(swizzle_forwardingTargetForSelector:)];
});
}
- (BOOL)swizzle_respondsToSelector:(SEL)aSelector {
if ([self swizzle_respondsToSelector:aSelector]) {
return YES;
}
if ([__checkString respondsToSelector:aSelector]) {
return YES;
}
return [super respondsToSelector:aSelector];
}
- (id)swizzle_forwardingTargetForSelector:(SEL)aSelector {
// whether NSString respondsToSelector
if ([__checkString respondsToSelector:aSelector]) {
return [NSString stringWithFormat:@"%@", self];
}
// Returns the object to which unrecognized messages should first be directed
return [super forwardingTargetForSelector:aSelector];
}
其實Runtime類似于跑酷,玩不好就會摔的很慘奠涌,斟酌使用此方法宪巨,最好的方式就是寫好自己的代碼邏輯。
2. 遇到crash怎么快速定位與解決
這里推薦一篇文章@念茜漫談iOS Crash收集框架, 推薦閱讀
補充一些大家常見的EXC_BAD_
錯誤原因
1)EXC_BAD_ACCESS
此類型的Excpetion是我們最長碰到的Crash溜畅,通常用于訪問了不改訪問的內(nèi)存導(dǎo)致捏卓。一般EXC_BAD_ACCESS后面的"()"還會帶有補充信息。
SIGSEGV:
通常由于重復(fù)釋放對象導(dǎo)致慈格,這種類型在切換了ARC以后應(yīng)該已經(jīng)很少見到了怠晴。
SIGABRT:
收到Abort信號退出,通常Foundation庫中的容器為了保護狀態(tài)正常會做一些檢測浴捆,例如插入nil到數(shù)組中等會遇到此類錯誤蒜田。
SEGV:
(Segmentation Violation),代表無效內(nèi)存地址选泻,比如空指針冲粤,未初始化指針,棧溢出等页眯;
SIGBUS:
總線錯誤梯捕,與 SIGSEGV 不同的是,SIGSEGV 訪問的是無效地址窝撵,而 SIGBUS 訪問的是有效地址傀顾,但總線訪問異常(如地址對齊問題)
SIGILL:
嘗試執(zhí)行非法的指令,可能不被識別或者沒有權(quán)限
2)EXC_BAD_INSTRUCTION
此類異常通常由于線程執(zhí)行非法指令導(dǎo)致碌奉。
1.在代碼中修改了storyboard與outlet的對應(yīng)關(guān)系短曾,但是storyboard沒有更新時發(fā)生過此crash。
2.與第三方庫中方法沖突時發(fā)生過此crash道批。
3.調(diào)用系統(tǒng)方法時傳入了不恰當?shù)闹羔橆愋汀?/p>
3)EXC_ARITHMETIC
代碼中做除法時分母為零了會發(fā)生此問題错英。
推薦兩個開源的Crash 收集庫
plcrashreporter:這是是相對比較早的Crash收集處理庫了,支付寶的開源協(xié)議上就有此庫隆豹。使用的話大致流程就是椭岩,注冊到APP,搜集Crash文件、上傳判哥。
更推薦KSCrash献雅,這個維護更新的比較多,可以了解一下