iOS開發(fā)中,如何防止Crash(閃退,崩潰)?

前言

移動APP中關(guān)于crash幾乎是0容忍的,那么iOS中會有很多引起crash,比如最常見的數(shù)組越界,添加空值。

如果你想解決大部分可能引起的crash,保持代碼的健壯性,又不想修改太多代碼,那么推薦你使用YCBStability

一款提高iOS穩(wěn)定性,有效防止閃退的框架

YCBStability

github下載

或者你可以通過cocoapods集成,在Podfile文件加入

pod 'YCBStability'

終端輸入命令:

pod install

記得導(dǎo)入 <YCBStability/YCBStability.h>

無需添加任何代碼,

Release: 不會crash
Debug: 為了更好的追蹤問題,依舊會crash,但提供了更多的crash信息

常見carsh匯總

接下來介紹一下,哪些方法使用不慎會引起crash,當(dāng)然就像上面說的,引入YCBStability會讓你的代碼更健壯,我在runtime中,進(jìn)行了方法攔截,避免了carsh

因此,你只要導(dǎo)入YCBStability,不需要添加任何代碼,你的代碼將變得足夠強(qiáng)壯

github地址

原理介紹

前面寫了很多關(guān)于YCBStability解決crash問題,如果你只是想解決代碼中的問題,讀到這里就夠了。

但如果你想了解更多知識,下面我來對crash進(jìn)行匯總,希望能幫助到你。

OC方法中的那些坑

OB提供的方法并不是健壯的,最常見的,set一個(gè)nil or數(shù)組越界都會引起crash,有很多朋友喜歡加一些判斷,我認(rèn)為這是一個(gè)良好的意識,但并不是最好的做法。

考慮到代碼的簡潔性,我建議你刪掉這些if-else,引入YCBStability

但如果你已經(jīng)用了Category來避免這些方法引起的crash,那么我建議你繼續(xù)Category

NSArray

方法 crash說明 :
- (ObjectType)objectAtIndex:(NSUInteger)index 當(dāng)index大于數(shù)組count的時(shí)候引起數(shù)組越界
- (NSUInteger)indexOfObject:(ObjectType)anObject 當(dāng)anObject為nil時(shí)carsh

NSMutableArray

方法 crash說明
- (void)addObject:(ObjectType)anObject 當(dāng)anObject為nil時(shí)carsh
- (void)insertObject:(ObjectType)anObject atIndex:(NSUInteger)index 當(dāng)anObject為nil時(shí)carsh,當(dāng)index>mutArray.count時(shí),會產(chǎn)生越界
- (void)removeObjectAtIndex:(NSUInteger)index 當(dāng)index>mutArray.count時(shí),會產(chǎn)生越界

NSMutableSet

方法 crash說明
- (void)addObject:(ObjectType)object 當(dāng)anObject為nil時(shí)carsh

NSMutableDictionary

方法 crash說明
- (void)setObject:(ObjectType)anObject forKey:(KeyType)aKey 當(dāng)anObject為nil時(shí),或key為nil時(shí),都會引起crash

泛型的坑

在NSDictionary中,我們經(jīng)常用到這個(gè)方法

- (nullable ObjectType)objectForKey:(KeyType)aKey;

這種返回值類型很容易產(chǎn)生坑,舉個(gè)列子:

項(xiàng)目API文檔服務(wù)器返回?cái)?shù)據(jù)如下

 {
   list :(
      'a',
      'b'
   )
}

這時(shí)候,你通過

NSArray *array = [dic objectForKey:@"list"];
NSString *str = [array firstObject];

正常狀態(tài)下,不會有任何問題,但是你要知道,服務(wù)器的數(shù)據(jù)是不可信的,有一天服務(wù)器代碼出現(xiàn)了bug,list不再是數(shù)組,那么APP就會Crash

{
    list: {}
 }

因?yàn)榇藭r(shí)的[dic objectForKey:@"list"];取出返回了Dic, 而你依然認(rèn)為是NSArray,并且調(diào)用了firstObject方法,Dic里沒有firstObject,APP會crash

面對服務(wù)器返回?cái)?shù)據(jù)的信任問題,有些同學(xué)養(yǎng)成了好習(xí)慣,加入了if-else,但是我希望你引入YCBStability,使用如下方法:

@interface NSDictionary (YCBStability)

/** 取key對應(yīng)的字符串 */
- (NSString *)getStringForKey:(id)key;

/** 取key對應(yīng)的數(shù)組 */
- (NSArray *)getArrayForKey:(id)key;

/** 取key對應(yīng)的字典 */
- (NSDictionary *)getDictinaryForKey:(id)key;

- (int)getIntForKey:(id)key;

- (float)getFloatForKey:(id)key;

- (BOOL)getBoolForKey:(id)key;

@end

根據(jù)你要的類型選擇不同的方法,

debug模式:如果和預(yù)期類型不符會crash,方便問題追蹤
release模式:我做了容錯(cuò)處理,避免了crash

非空判斷

為了更好的支持類型判斷,我提供了如下方法供使用

@interface YCBNonEmpty : NSObject

/** 判斷是否是非空的數(shù)組 */
+ (BOOL)isArray:(id)object;

/** 判斷是否是非空的集合*/
+ (BOOL)isSet:(id)object;

/** 判斷是否是非空的字符串 */
+ (BOOL)isString:(id)text;

/** 判斷是否是非空的字典 */
+ (BOOL)isDictionary:(id)object;

@end

非空判斷是代碼中經(jīng)常用到的技巧,以保證代碼的健壯性,在YCBNonEmpty中,我依據(jù)類型和count兩個(gè)條件,判斷非空,更加安全準(zhǔn)確。

未來

release模式雖然規(guī)避了Crash,保證了用戶體驗(yàn)。但是犧牲了對問題的追蹤。未來我希望可以把日志記錄到本地,你可以通過項(xiàng)目中已經(jīng)集成得友盟統(tǒng)計(jì),百度統(tǒng)計(jì),又或者是自己的接口,進(jìn)行數(shù)據(jù)上報(bào),追蹤問題。

期待v2.0吧!

歡迎大家關(guān)注下我,一起交流,一起學(xué)習(xí)!

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

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

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