iOS崩潰異常處理(使用篇)

在開發APP的過程中,崩潰等異常總是讓我們不堪其煩,不過開發階段的崩潰等問題,都是小事,可以進行處理,但是一旦發布的版本出現崩潰的問題,那就是大問題,不僅要連夜更新版本,還要為找這個bug不斷的嘗試,所以,我總結了看到的一些對于崩潰等異常的處理,以備自己日后參考。
若有可以改進的,望各位大大不吝賜教。
(注:本文只介紹使用方法,不對原理做深層解析,小弟也沒這水平,接下來閑下來了,在研究代碼的實現原理,出一篇原理篇~)

一、關于崩潰

閃退估計是我們最不想看到的,對于用戶而言,馬上就能產生一種不悅,對于投資方而言,也會產生對技術實力的不信任感,所以,我們就需要對閃退進行處理,這里介紹一個不錯的三方:AvoidCrash,寫這個的大大也很牛逼,原文參照這里

這個三方可以處理例如插入空值到字典中或數組中引起的崩潰、數組越界引起的崩潰、unrecognized selector sent to instance等等的崩潰,都能捕獲并且避免閃退。

對于插入空值、越界等,原理比較簡單,就是利用Runtime的方法交換,把普通的插入和取值的方法,替換成安全插入和安全讀取的方法,具體代碼可以去看源碼。
話不多說,先上效果:
以下是可導致崩潰的代碼:

    NSString *nilStr = nil;
    NSArray *array = @[@"chenfanfang", nilStr];

崩潰截圖

若有AvoidCrash來防止崩潰,則不會崩潰,并且會將原本會崩潰情況的詳細信息打印出來,如下圖:
防止崩潰的效果

效果不錯吧,接下來上使用步驟:

  • 集成:
    建議使用cocoapod,僅需要pod AvoidCrash一句話即可。(手動導入的步驟,可以參照上面所說的原文)。

  • 使用方法:(只要在AppDelegatedidFinishLaunchingWithOptions方法中調用avoidCrash方法,就可以開始監聽異常。)

- (void)avoidCrash {
    
    /*
     * 項目初期不需要對"unrecognized selector sent to instance"錯誤進行處理,因為還沒有相關的崩潰的類
     * 后期出現后,再使用makeAllEffective方法,把所有對應崩潰的類添加到數組中,避免崩潰
     * 對于正式線可以啟用該方法,測試線建議關閉該方法
     */
    [AvoidCrash becomeEffective];
    
    
//    [AvoidCrash makeAllEffective];
//    NSArray *noneSelClassStrings = @[
//                                     @"NSString"
//                                     ];
//    [AvoidCrash setupNoneSelClassStringsArr:noneSelClassStrings];
    
    
    //監聽通知:AvoidCrashNotification, 獲取AvoidCrash捕獲的崩潰日志的詳細信息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil];
}
  • 再監聽異常的通知:
- (void)dealwithCrashMessage:(NSNotification *)notification {
    MYLog(@"\n??\n??監測到崩潰信息??\n??\n");
    /*
     * 在這邊對避免的異常進行一些處理,比如上傳到日志服務器等。
     */
}
以上就是避免崩潰的簡單用法,關于能處理哪些異常,可以自行查看Git中的項目介紹。

二、關于異常的統計

上述的方法,能夠避免崩潰,但是不能夠避免所有狀況的崩潰,作者也在不斷的根據用戶的使用情況進行更新,盡量對所有已知的崩潰進行避免。所以,我們還需要對異常進行其他的收集,也能有效的幫助自己改進APP。

這里僅做騰訊的Bugly進行介紹,因為其他的例如友盟、極光的,個人感覺都沒有Bugly好用,我也就不做介紹了,有興趣的可以自行了解。
這里參照的文章原文在此

  • 集成
    集成很簡單,按照官方文檔來就好,我們這里建個簡單的小項目,模擬一些崩潰,測試下Bugly的bug上報及時性。
    項目就取名叫NSException了,創建好項目后,去Bugly的控制臺,添加我們的應用。
    添加應用

    創建完應用,進入下一個界面,我們選擇異常上報。
    選擇異常上報

    再到我們的APP的appDelegatedidFinishLaunchingWithOptions方法內調用初始化方法即可。
// 頭文件
#import <Bugly/Bugly.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [Bugly startWithAppId:@"此處替換為你的AppId"];

    return YES;
}

AppID可以點擊你在控制臺創建的App,然后點產品設置就能看到了。


查看appid
  • Bug上傳測試
    接下來我們在ViewConroller中隨便創造一個閃退的bug
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSArray *arr = @[@"", @""];
    arr[5];
}

運行,崩潰,刷新Bugly的控制臺,你會發現,bug已經統計到了。所以,Bugly的崩潰上傳是在崩潰后立刻上傳的。


控制臺記錄的崩潰信息

我們點進異常問題中去看一下,崩潰信息大致是這樣的,我們可以很直觀的看到崩在哪個方法里了。


異常信息

進階

如果我們就這樣使用Bugly是不是太可惜了,我們來看看Bugly還有什么功能;查看頭文件,會發現Bugly有三個類暴露出來,分別是BuglyBuglyConfigBuglyLog

1.BuglyConfig類主要用于個性話配置Bugly類,由一些屬性和BuglyDelegate代理組成。
  • 屬性:BuglyConfig大部分屬性有設有默認值,一般不用更改,但是關于卡頓監控的屬性確是默認關閉的:
/**
*  卡頓監控開關,默認關閉
*/
@property (nonatomic) BOOL blockMonitorEnable;
/**
*  卡頓監控判斷間隔,單位為秒
*/
@property (nonatomic) NSTimeInterval blockMonitorTimeout;

如果需要上報卡頓,只需要將blockMonitorEnable設為true,給blockMonitorTimeout設置一個合理的值即可;

  • 代理:BuglyConfig可以設置一個代理,來自定義上傳崩潰的附屬信息;
@protocol BuglyDelegate <NSObject>

@optional
/**
*  發生異常時回調
*  @param exception 異常信息
*  @return 返回需上報記錄,隨異常上報一起上報
*/
- (NSString * BLY_NULLABLE)attachmentForException:(NSException * BLY_NULLABLE)exception;
@end

我們的初始化就改成:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    BuglyConfig *config = [[BuglyConfig alloc] init];
    //監聽卡頓
    config.blockMonitorEnable = YES;
    config.blockMonitorTimeout = 3;
    config.consolelogEnable = YES;
    config.delegate = self;
    [Bugly startWithAppId:@"此處替換為你的AppId" config:config];
//    [self avoidCrash];
    return YES;
}
- (NSString *)attachmentForException:(NSException *)exception {
    NSLog(@"異常事件代理");
    return [NSString stringWithFormat:@"TEST: %@",exception.userInfo];
}

再運行一次,崩潰,然后我們看看Bugly控制臺上報記錄:


留意紅色邊框內的文件

文件內部記錄的就是異常的代理方法所上報的內容。

2.上傳打印日志,BuglyLog類主要用于打印日志,有6種級別:
typedef NS_ENUM(NSUInteger, BuglyLogLevel) {
  BuglyLogLevelSilent  = 0,
  BuglyLogLevelError   = 1,
  BuglyLogLevelWarn    = 2,
  BuglyLogLevelInfo    = 3,
  BuglyLogLevelDebug   = 4,
  BuglyLogLevelVerbose = 5,
};

BuglyLog除了控制臺打印,還有一個重要功能就是上報打印內容,內容將在崩潰時一同被上報;但是這個功能是默認不上報的,需要配置BuglyConfig的reportLogLevel屬性;如config.reportLogLevel = BuglyLogLevelWarn,將會上報BuglyLogLevelWarn和BuglyLogLevelError級別的打印日志。

3.自定義上報異常,我們再回到Bugly類,除了初始化Bugly的方法外,還有一些其他的方法:

自定義上報錯誤

/**
*  上報自定義異常
*  @param exception 異常信息
*/
+ (void)reportException:(nonnull NSException *)exception;
/**
*  上報錯誤
*  @param error 錯誤信息
*/
+ (void)reportError:(NSError *)error;

重點來了!!!!

配合上AvoidCrash,使用上報自定義異常方法,我們就既能避免崩潰,又能監聽異常!

//AvoidCrash異常通知監聽方法,在這里我們可以調用reportException方法進行上報
- (void)dealwithCrashMessage:(NSNotification *)notification {
    NSLog(@"\n??\n??監測到崩潰信息??\n??\n");
    
    NSException *exception = [NSException exceptionWithName:@"AvoidCrash" reason:[notification valueForKeyPath:@"userInfo.errorName"] userInfo:notification.userInfo];
    [Bugly reportException:exception];
}

以上就是AvoidCrash+Bugly優化APP的運行處理。

雖然Bugly的崩潰列表中我們能看到得到代碼的崩潰信息,但想更具體的分析代碼位置,就要用到符號表了。

三、符號表

沒有符號表,我們就無法定位崩潰中的符號對應的代碼所在的類以及類中的行數位置。我們在每次構建版本、debug的時候,都會生成dSYM后綴名的符號表文件,而我們App在手機上運行的時候,崩潰后產生的崩潰信息,不可能定位到代碼的多少多少行,因為這些信息對于App運行是沒有意義的,存儲在App中勢必會增大安裝包的體積,所以App的崩潰信息都是存儲為各種符號,具體符號代表什么,需要去符號表中查找對應的含義。
我們每次debug、構建版本,都會生成dSYM文件,都對應了一個UUID(像我們的手機一樣,都有一個唯一標志),按下圖指示,我們就能找到我們所使用的App版本對應的dSYM文件的UUID,通過這個UUID,我們就能找到存儲在我們電腦中的dSYM文件,將這個文件上傳到bugly,bugly會自動幫我們找到崩潰符號的含義。

查看符號表文件

需要注意的是,構建版本會自動生成dSYM文件,但debug的時候,是沒有的,需要我們手動開啟。在build setting中搜索debug,將下面兩項內容修改為正確的設置:
手動開始debug模式下的生成dSYM文件

有了符號表的UUID,我們打開終端,按UUID找到符號表的路徑。
mdfind "com_apple_xcode_dsym_uuids == A8E87810-70A7-3335-B638-C8B01BE15D79"
后面的一串字母數字組合,就是我們的UUID,這里需要將UUID按一定格式處理下,也就是在特定位置插入“-”,具體格式如下:
處理UUID

來到終端,運行上面的命令,就定位到了dSYM文件的位置:
定位dSYM文件

打開文件路徑,就找到了dSYM文件:
找到dSYM文件

拷貝出來,壓縮為zip文件,上傳到bugly上。
上傳文件

刷新頁面,再回去看剛才的問題,定位到了為ViewController.m的第24行:
重新查看異常

這樣我們就定位到了有問題的地方。

官網文檔也提供了自動上傳dSYM文件的操作流程,有興趣的可以試試,避免以后每次新版本都要手動上傳dSYM文件。

dSYM文件也可以手動查找:


手動查找dSYM文件

找到你構建的版本,右鍵show in finder:


查看finder中路徑

然后在定位到的文件上右鍵顯示包內容就OK了:


包內查找dSYM文件

總結

以上就是Bugly收集異常的過程,由于我也只是剛剛接觸Bugly,所以自己也有幾個問題沒有解決,例如對于Bugly的符號表的dSYM文件的上傳,每次新版本dSYM文件都會改變?那手動是有點麻煩,自動的方法也得去看看。

還有很多需要深入學習的,我也會繼續學習繼續分享,同樣的,希望各位大大能夠指出一些可以改進的或者理解有誤的,幫助小弟進步,例如AvoidCrash作者所說的“一些處理”,有的話萬分感激。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容

  • 該文章屬于劉小壯原創,轉載請注明:劉小壯[http://www.lxweimin.com/u/2de707c93d...
    劉小壯閱讀 37,642評論 45 122
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,692評論 25 708
  • 前言 先說下友盟的SDK,現在真是對友盟沒脾氣了,分享不正常!三方登錄不正常!崩潰分析也不好用!最近所在項目的Ap...
    翻炒吧蛋滾飯閱讀 22,701評論 43 53
  • 什么是符號表? 符號表是內存地址與函數名、文件名、行號的映射表。符號表元素如下所示: <起始地址> <結束地址> ...
    深圳陽光閱讀 12,229評論 28 5
  • css3新增了一個好玩的屬性:animation,雖然用它做出來的動畫并沒有多么炫酷流暢,但是它減少了代碼量并且在...
    sakatayui醬閱讀 10,294評論 0 2