AvoidCrash -- 遠離常見的崩潰

源碼地址: AvoidCrash

https://github.com/chenfanfang/AvoidCrash

前言

一個已經發布到AppStore上的App,最忌諱的就是崩潰問題。為什么在開發階段或者測試階段都不會崩潰,而發布到AppStore上就崩潰了呢?究其根源,最主要的原因就是數據的錯亂。特別是 服務器返回數據的錯亂,將嚴重影響到我們的App。


Foundation框架存在許多潛在崩潰的危險

  • 將 nil 插入可變數組中會導致崩潰。
  • 數組越界會導致崩潰。
  • 根據key給字典某個元素重新賦值時,若key為 nil 會導致崩潰。
  • ......

AvoidCrash簡介

  • 這個框架利用runtime技術對一些常用并且容易導致崩潰的方法進行處理,可以有效的防止崩潰。
  • 并且打印出具體是哪個方法會導致崩潰,讓你快速定位導致崩潰的代碼。
  • 你可以獲取到原本導致崩潰的主要信息<由于這個框架的存在,并不會崩潰>,進行相應的處理。比如:
    • 你可以將這些崩潰信息發送到自己服務器。
    • 你若集成了第三方崩潰日志收集的SDK,比如你用了騰訊的Bugly,你可以上報自定義異常。
  • 或許你會問有JSPatch就可以下發補丁來修復bug,為什么要用AvoidCrash?我只能說,AvoidCrash可以有效防止部分常見崩潰,JSPatch可以快速修復bug.推薦將兩者都集成到項目中去。

下面先來看下防止崩潰的效果吧

可導致崩潰的代碼

    NSString *nilStr = nil;
    NSArray *array = @[@"chenfanfang", nilStr];
  • 若沒有AvoidCrash來防止崩潰,則會直接崩潰,如下圖
崩潰截圖.png
  • 若有AvoidCrash來防止崩潰,則不會崩潰,并且會將原本會崩潰情況的詳細信息打印出來,如下圖
防止崩潰的輸出日志.png

Installation【安裝】

From CocoaPods【使用CocoaPods】

pod  AvoidCrash

Manually【手動導入】

  • Drag all source files under floder AvoidCrash to your project.【將AvoidCrash文件夾中的所有源代碼拽入項目中】
  • 對 NSMutableArray+AvoidCrash.m 文件進行 -fno-objc-arc 設置(若使用CocoaPods集成則無需手動配置),配置過程如下圖:
配置mutableArray.png

使用方法

  • 在AppDelegate的didFinishLaunchingWithOptions方法中添加如下代碼,讓AvoidCrash生效
//這句代碼會讓AvoidCrash生效,若沒有如下代碼,則AvoidCrash就不起作用
[AvoidCrash becomeEffective];

   /*
    *  [AvoidCrash becomeEffective],是全局生效。若你只需要部分生效,你可以單個進行處理,比如:
    *  [NSArray avoidCrashExchangeMethod];
    *  [NSMutableArray avoidCrashExchangeMethod];
    *  .................
    *  .................
    */
  • 若你想要獲取崩潰日志的所有詳細信息,只需添加通知的監聽,監聽的通知名為:AvoidCrashNotification
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [AvoidCrash becomeEffective];
    
    //監聽通知:AvoidCrashNotification, 獲取AvoidCrash捕獲的崩潰日志的詳細信息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil];
    return YES;
}

- (void)dealwithCrashMessage:(NSNotification *)note {
    //注意:所有的信息都在userInfo中
    //你可以在這里收集相應的崩潰信息進行相應的處理(比如傳到自己服務器)
    NSLog(@"%@",note.userInfo);
}
  • 下面通過打斷點的形式來看下userInfo中的信息結構,看下包含了哪些信息
userInfo信息結構.png
  • 再看下控制臺輸出日志來看下userInfo中的包含了哪些信息
userInfo詳細信息.png

目前可以防止崩潰的方法有


  • NSArray
    • 1. NSArray的快速創建方式 NSArray *array = @[@"chenfanfang", @"AvoidCrash"]; //這種創建方式其實調用的是2中的方法

    • 2. +(instancetype)arrayWithObjects:(const id _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt

    • 3. 通過下標獲取元素 array[100]、[array objectAtIndex:100]

      • - (id)objectAtIndex:(NSUInteger)index
    • 4. - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes

    • 5. - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range


  • NSMutableArray
    • 1. 通過下標獲取元素 array[100]、[array objectAtIndex:100]
      • - (id)objectAtIndex:(NSUInteger)index
    • 2. - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx
    • 3. - (void)removeObjectAtIndex:(NSUInteger)index
    • 4. - (void)insertObject:(id)anObject atIndex:(NSUInteger)index
    • 5. - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes
    • 6. - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range

  • NSDictionary
    • 1. NSDictionary的快速創建方式 NSDictionary *dict = @{@"frameWork" : @"AvoidCrash"}; //這種創建方式其實調用的是2中的方法
    • 2. +(instancetype)dictionaryWithObjects:(const id _Nonnull __unsafe_unretained *)objects forKeys:(const id<NSCopying> _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt

  • NSMutableDictionary
    • 1. - (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey
    • 2. - (void)removeObjectForKey:(id)aKey

  • NSString
    • 1. - (unichar)characterAtIndex:(NSUInteger)index
    • 2. - (NSString *)substringFromIndex:(NSUInteger)from
    • 3. - (NSString *)substringToIndex:(NSUInteger)to {
    • 4. - (NSString *)substringWithRange:(NSRange)range {
    • 5. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement
    • 6. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange
    • 7. - (NSString *)stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement

  • NSMutableString
    • 1. 由于NSMutableString是繼承于NSString,所以這里和NSString有些同樣的方法就不重復寫了
    • 2. - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString
    • 3. - (void)insertString:(NSString *)aString atIndex:(NSUInteger)loc
    • 4. - (void)deleteCharactersInRange:(NSRange)range

  • KVC
    • 1.- (void)setValue:(id)value forKey:(NSString *)key
    • 2.- (void)setValue:(id)value forKeyPath:(NSString *)keyPath
    • 3.- (void)setValue:(id)value forUndefinedKey:(NSString *)key //這個方法一般用來重寫,不會主動調用
    • 4.- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues

  • NSAttributedString
  • 1.- (instancetype)initWithString:(NSString *)str
  • 2.- (instancetype)initWithAttributedString:(NSAttributedString *)attrStr
  • 3.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs

  • NSMutableAttributedString
  • 1.- (instancetype)initWithString:(NSString *)str
  • 2.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs

更新

2016-10-15

  • 修復上一個版本部分方法不能攔截崩潰的BUG,具體修復哪些可以查看issues和簡書上的留言。
  • 優化崩潰代碼的定位,定位崩潰代碼更加準確。
  • 增加對KVC賦值防止崩潰的處理。
  • 增加對NSAttributedString防止崩潰的處理
  • 增加對NSMutableAttributedString防止崩潰的處理

2016-11-29

  • 修復在鍵盤彈出狀態下,按Home鍵進入后臺會導致崩潰的bug。
  • 新增防止崩潰(NSArray、NSMutableArray) - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes

2016-12-1

  • 處理數組的類簇問題,提高兼容性,不論是由于array[100]方式,還是[array objectAtIndex:100]方式 獲取數組中的某個元素操作不當而導致的crash,都能被攔截防止崩潰。

  • 上一個版本只能防止array[100]導致的崩潰,不能防止[array objectAtIndex:100]導致的崩潰。

  • 統一對線程進行處理,監聽通知AvoidCrashNotification后,不論是在主線程導致的crash還是在子線程導致的crash,監聽通知的方法統一在"主線程"中。

  • 上一個版本中,在哪個線程導致的crash, 則監聽通知的方法就在哪個線程中。

  • 新增防止崩潰 (NSArray、NSMutableArray) - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range

期待

  • 如果你發現了哪些常用的Foundation中的方法存在潛在崩潰的危險,而這個框架中沒有進行處理,希望你能 issue, 或者在簡書私信我,我將這些方法也添加到AvoidCrash中。謝謝
  • 如果你在使用過程中遇到BUG,希望你能 issue, 或者在簡書私信我。謝謝(或者嘗試下載最新的框架代碼看看BUG修復沒有)
  • 畢竟一個人的能力有限,時間有限,希望有能力的你可以加入到這個項目中來,一起完善AvoidCrash。請Pull Requests我。

About me -- 簡書










最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容