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

在開(kāi)發(fā)APP的過(guò)程中泪酱,崩潰等異常總是讓我們不堪其煩,不過(guò)開(kāi)發(fā)階段的崩潰等問(wèn)題墓阀,都是小事毡惜,可以進(jìn)行處理,但是一旦發(fā)布的版本出現(xiàn)崩潰的問(wèn)題斯撮,那就是大問(wèn)題经伙,不僅要連夜更新版本,還要為找這個(gè)bug不斷的嘗試勿锅,所以帕膜,我總結(jié)了看到的一些對(duì)于崩潰等異常的處理,以備自己日后參考溢十。
若有可以改進(jìn)的垮刹,望各位大大不吝賜教。
(注:本文只介紹使用方法茶宵,不對(duì)原理做深層解析危纫,小弟也沒(méi)這水平,接下來(lái)閑下來(lái)了乌庶,在研究代碼的實(shí)現(xiàn)原理种蝶,出一篇原理篇~)

一、關(guān)于崩潰

閃退估計(jì)是我們最不想看到的瞒大,對(duì)于用戶而言螃征,馬上就能產(chǎn)生一種不悅,對(duì)于投資方而言透敌,也會(huì)產(chǎn)生對(duì)技術(shù)實(shí)力的不信任感盯滚,所以,我們就需要對(duì)閃退進(jìn)行處理酗电,這里介紹一個(gè)不錯(cuò)的三方:AvoidCrash魄藕,寫這個(gè)的大大也很牛逼,原文參照這里撵术。

這個(gè)三方可以處理例如插入空值到字典中或數(shù)組中引起的崩潰背率、數(shù)組越界引起的崩潰、unrecognized selector sent to instance等等的崩潰嫩与,都能捕獲并且避免閃退寝姿。

對(duì)于插入空值、越界等划滋,原理比較簡(jiǎn)單饵筑,就是利用Runtime的方法交換,把普通的插入和取值的方法处坪,替換成安全插入和安全讀取的方法根资,具體代碼可以去看源碼架专。
話不多說(shuō),先上效果:
以下是可導(dǎo)致崩潰的代碼:

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

崩潰截圖

若有AvoidCrash來(lái)防止崩潰嫂冻,則不會(huì)崩潰胶征,并且會(huì)將原本會(huì)崩潰情況的詳細(xì)信息打印出來(lái),如下圖:
防止崩潰的效果

效果不錯(cuò)吧桨仿,接下來(lái)上使用步驟:

  • 集成:
    建議使用cocoapod睛低,僅需要pod AvoidCrash一句話即可。(手動(dòng)導(dǎo)入的步驟服傍,可以參照上面所說(shuō)的原文)钱雷。

  • 使用方法:(只要在AppDelegatedidFinishLaunchingWithOptions方法中調(diào)用avoidCrash方法,就可以開(kāi)始監(jiān)聽(tīng)異常吹零。)

- (void)avoidCrash {
    
    /*
     * 項(xiàng)目初期不需要對(duì)"unrecognized selector sent to instance"錯(cuò)誤進(jìn)行處理罩抗,因?yàn)檫€沒(méi)有相關(guān)的崩潰的類
     * 后期出現(xiàn)后,再使用makeAllEffective方法灿椅,把所有對(duì)應(yīng)崩潰的類添加到數(shù)組中套蒂,避免崩潰
     * 對(duì)于正式線可以啟用該方法,測(cè)試線建議關(guān)閉該方法
     */
    [AvoidCrash becomeEffective];
    
    
//    [AvoidCrash makeAllEffective];
//    NSArray *noneSelClassStrings = @[
//                                     @"NSString"
//                                     ];
//    [AvoidCrash setupNoneSelClassStringsArr:noneSelClassStrings];
    
    
    //監(jiān)聽(tīng)通知:AvoidCrashNotification, 獲取AvoidCrash捕獲的崩潰日志的詳細(xì)信息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil];
}
  • 再監(jiān)聽(tīng)異常的通知:
- (void)dealwithCrashMessage:(NSNotification *)notification {
    MYLog(@"\n??\n??監(jiān)測(cè)到崩潰信息??\n??\n");
    /*
     * 在這邊對(duì)避免的異常進(jìn)行一些處理茫蛹,比如上傳到日志服務(wù)器等操刀。
     */
}
以上就是避免崩潰的簡(jiǎn)單用法,關(guān)于能處理哪些異常婴洼,可以自行查看Git中的項(xiàng)目介紹骨坑。

二、關(guān)于異常的統(tǒng)計(jì)

上述的方法柬采,能夠避免崩潰欢唾,但是不能夠避免所有狀況的崩潰,作者也在不斷的根據(jù)用戶的使用情況進(jìn)行更新粉捻,盡量對(duì)所有已知的崩潰進(jìn)行避免礁遣。所以,我們還需要對(duì)異常進(jìn)行其他的收集肩刃,也能有效的幫助自己改進(jìn)APP亡脸。

這里僅做騰訊的Bugly進(jìn)行介紹,因?yàn)槠渌睦缬衙耸骼摇O光的,個(gè)人感覺(jué)都沒(méi)有Bugly好用大州,我也就不做介紹了续语,有興趣的可以自行了解。
這里參照的文章原文在此厦画。

  • 集成
    集成很簡(jiǎn)單疮茄,按照官方文檔來(lái)就好滥朱,我們這里建個(gè)簡(jiǎn)單的小項(xiàng)目,模擬一些崩潰力试,測(cè)試下Bugly的bug上報(bào)及時(shí)性徙邻。
    項(xiàng)目就取名叫NSException了,創(chuàng)建好項(xiàng)目后畸裳,去Bugly的控制臺(tái)缰犁,添加我們的應(yīng)用。
    添加應(yīng)用

    創(chuàng)建完應(yīng)用怖糊,進(jìn)入下一個(gè)界面帅容,我們選擇異常上報(bào)。
    選擇異常上報(bào)

    再到我們的APP的appDelegatedidFinishLaunchingWithOptions方法內(nèi)調(diào)用初始化方法即可伍伤。
// 頭文件
#import <Bugly/Bugly.h>

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

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

    return YES;
}

AppID可以點(diǎn)擊你在控制臺(tái)創(chuàng)建的App并徘,然后點(diǎn)產(chǎn)品設(shè)置就能看到了。


查看appid
  • Bug上傳測(cè)試
    接下來(lái)我們?cè)赩iewConroller中隨便創(chuàng)造一個(gè)閃退的bug
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSArray *arr = @[@"", @""];
    arr[5];
}

運(yùn)行扰魂,崩潰麦乞,刷新Bugly的控制臺(tái),你會(huì)發(fā)現(xiàn)劝评,bug已經(jīng)統(tǒng)計(jì)到了姐直。所以,Bugly的崩潰上傳是在崩潰后立刻上傳的付翁。


控制臺(tái)記錄的崩潰信息

我們點(diǎn)進(jìn)異常問(wèn)題中去看一下简肴,崩潰信息大致是這樣的,我們可以很直觀的看到崩在哪個(gè)方法里了百侧。


異常信息

進(jìn)階

如果我們就這樣使用Bugly是不是太可惜了砰识,我們來(lái)看看Bugly還有什么功能;查看頭文件佣渴,會(huì)發(fā)現(xiàn)Bugly有三個(gè)類暴露出來(lái)辫狼,分別是BuglyBuglyConfigBuglyLog辛润。

1.BuglyConfig類主要用于個(gè)性話配置Bugly類膨处,由一些屬性和BuglyDelegate代理組成。
  • 屬性:BuglyConfig大部分屬性有設(shè)有默認(rèn)值砂竖,一般不用更改真椿,但是關(guān)于卡頓監(jiān)控的屬性確是默認(rèn)關(guān)閉的:
/**
*  卡頓監(jiān)控開(kāi)關(guān),默認(rèn)關(guān)閉
*/
@property (nonatomic) BOOL blockMonitorEnable;
/**
*  卡頓監(jiān)控判斷間隔乎澄,單位為秒
*/
@property (nonatomic) NSTimeInterval blockMonitorTimeout;

如果需要上報(bào)卡頓突硝,只需要將blockMonitorEnable設(shè)為true,給blockMonitorTimeout設(shè)置一個(gè)合理的值即可置济;

  • 代理:BuglyConfig可以設(shè)置一個(gè)代理解恰,來(lái)自定義上傳崩潰的附屬信息锋八;
@protocol BuglyDelegate <NSObject>

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

我們的初始化就改成:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    BuglyConfig *config = [[BuglyConfig alloc] init];
    //監(jiān)聽(tīng)卡頓
    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];
}

再運(yùn)行一次护盈,崩潰挟纱,然后我們看看Bugly控制臺(tái)上報(bào)記錄:


留意紅色邊框內(nèi)的文件

文件內(nèi)部記錄的就是異常的代理方法所上報(bào)的內(nèi)容。

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

BuglyLog除了控制臺(tái)打印,還有一個(gè)重要功能就是上報(bào)打印內(nèi)容脏款,內(nèi)容將在崩潰時(shí)一同被上報(bào);但是這個(gè)功能是默認(rèn)不上報(bào)的围苫,需要配置BuglyConfig的reportLogLevel屬性;如config.reportLogLevel = BuglyLogLevelWarn撤师,將會(huì)上報(bào)BuglyLogLevelWarn和BuglyLogLevelError級(jí)別的打印日志剂府。

3.自定義上報(bào)異常,我們?cè)倩氐紹ugly類剃盾,除了初始化Bugly的方法外腺占,還有一些其他的方法:

自定義上報(bào)錯(cuò)誤

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

重點(diǎn)來(lái)了!Q髑础Kゲ!

配合上AvoidCrash积蔚,使用上報(bào)自定義異常方法意鲸,我們就既能避免崩潰,又能監(jiān)聽(tīng)異常尽爆!

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

以上就是AvoidCrash+Bugly優(yōu)化APP的運(yùn)行處理。

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

三幅狮、符號(hào)表

沒(méi)有符號(hào)表募强,我們就無(wú)法定位崩潰中的符號(hào)對(duì)應(yīng)的代碼所在的類以及類中的行數(shù)位置。我們?cè)诿看螛?gòu)建版本崇摄、debug的時(shí)候擎值,都會(huì)生成dSYM后綴名的符號(hào)表文件,而我們App在手機(jī)上運(yùn)行的時(shí)候逐抑,崩潰后產(chǎn)生的崩潰信息幅恋,不可能定位到代碼的多少多少行,因?yàn)檫@些信息對(duì)于App運(yùn)行是沒(méi)有意義的泵肄,存儲(chǔ)在App中勢(shì)必會(huì)增大安裝包的體積捆交,所以App的崩潰信息都是存儲(chǔ)為各種符號(hào),具體符號(hào)代表什么腐巢,需要去符號(hào)表中查找對(duì)應(yīng)的含義品追。
我們每次debug、構(gòu)建版本冯丙,都會(huì)生成dSYM文件肉瓦,都對(duì)應(yīng)了一個(gè)UUID(像我們的手機(jī)一樣,都有一個(gè)唯一標(biāo)志)胃惜,按下圖指示泞莉,我們就能找到我們所使用的App版本對(duì)應(yīng)的dSYM文件的UUID,通過(guò)這個(gè)UUID船殉,我們就能找到存儲(chǔ)在我們電腦中的dSYM文件鲫趁,將這個(gè)文件上傳到bugly,bugly會(huì)自動(dòng)幫我們找到崩潰符號(hào)的含義利虫。

查看符號(hào)表文件

需要注意的是挨厚,構(gòu)建版本會(huì)自動(dòng)生成dSYM文件,但debug的時(shí)候糠惫,是沒(méi)有的疫剃,需要我們手動(dòng)開(kāi)啟。在build setting中搜索debug硼讽,將下面兩項(xiàng)內(nèi)容修改為正確的設(shè)置:
手動(dòng)開(kāi)始debug模式下的生成dSYM文件

有了符號(hào)表的UUID巢价,我們打開(kāi)終端,按UUID找到符號(hào)表的路徑固阁。
mdfind "com_apple_xcode_dsym_uuids == A8E87810-70A7-3335-B638-C8B01BE15D79"
后面的一串字母數(shù)字組合壤躲,就是我們的UUID,這里需要將UUID按一定格式處理下您炉,也就是在特定位置插入“-”柒爵,具體格式如下:
處理UUID

來(lái)到終端,運(yùn)行上面的命令赚爵,就定位到了dSYM文件的位置:
定位dSYM文件

打開(kāi)文件路徑棉胀,就找到了dSYM文件:
找到dSYM文件

拷貝出來(lái),壓縮為zip文件冀膝,上傳到bugly上唁奢。
上傳文件

刷新頁(yè)面,再回去看剛才的問(wèn)題窝剖,定位到了為ViewController.m的第24行:
重新查看異常

這樣我們就定位到了有問(wèn)題的地方麻掸。

官網(wǎng)文檔也提供了自動(dòng)上傳dSYM文件的操作流程,有興趣的可以試試赐纱,避免以后每次新版本都要手動(dòng)上傳dSYM文件脊奋。

dSYM文件也可以手動(dòng)查找:


手動(dòng)查找dSYM文件

找到你構(gòu)建的版本熬北,右鍵show in finder:


查看finder中路徑

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


包內(nèi)查找dSYM文件

總結(jié)

以上就是Bugly收集異常的過(guò)程,由于我也只是剛剛接觸Bugly诚隙,所以自己也有幾個(gè)問(wèn)題沒(méi)有解決讶隐,例如對(duì)于Bugly的符號(hào)表的dSYM文件的上傳,每次新版本dSYM文件都會(huì)改變久又?那手動(dòng)是有點(diǎn)麻煩巫延,自動(dòng)的方法也得去看看。

還有很多需要深入學(xué)習(xí)的地消,我也會(huì)繼續(xù)學(xué)習(xí)繼續(xù)分享炉峰,同樣的,希望各位大大能夠指出一些可以改進(jìn)的或者理解有誤的脉执,幫助小弟進(jìn)步疼阔,例如AvoidCrash作者所說(shuō)的“一些處理”,有的話萬(wàn)分感激适瓦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末竿开,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子玻熙,更是在濱河造成了極大的恐慌否彩,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗦随,死亡現(xiàn)場(chǎng)離奇詭異列荔,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)枚尼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門贴浙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人署恍,你說(shuō)我怎么就攤上這事崎溃。” “怎么了盯质?”我有些...
    開(kāi)封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵袁串,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我呼巷,道長(zhǎng)囱修,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任王悍,我火速辦了婚禮破镰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己鲜漩,他們只是感情好源譬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著孕似,像睡著了一般瓶佳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鳞青,一...
    開(kāi)封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音为朋,去河邊找鬼臂拓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛习寸,可吹牛的內(nèi)容都是我干的胶惰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼霞溪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼孵滞!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鸯匹,我...
    開(kāi)封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坊饶,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后殴蓬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體匿级,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年染厅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痘绎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肖粮,死狀恐怖孤页,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涩馆,我是刑警寧澤行施,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站凌净,受9級(jí)特大地震影響悲龟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜冰寻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一须教、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦轻腺、人聲如沸乐疆。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挤土。三九已至,卻和暖如春误算,著一層夾襖步出監(jiān)牢的瞬間仰美,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工儿礼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咖杂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓蚊夫,卻偏偏與公主長(zhǎng)得像诉字,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子知纷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 該文章屬于劉小壯原創(chuàng)壤圃,轉(zhuǎn)載請(qǐng)注明:劉小壯[http://www.reibang.com/u/2de707c93d...
    劉小壯閱讀 37,571評(píng)論 45 122
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,108評(píng)論 25 707
  • 前言 先說(shuō)下友盟的SDK,現(xiàn)在真是對(duì)友盟沒(méi)脾氣了琅轧,分享不正常伍绳!三方登錄不正常!崩潰分析也不好用鹰晨!最近所在項(xiàng)目的Ap...
    翻炒吧蛋滾飯閱讀 22,584評(píng)論 43 53
  • 什么是符號(hào)表墨叛? 符號(hào)表是內(nèi)存地址與函數(shù)名、文件名模蜡、行號(hào)的映射表漠趁。符號(hào)表元素如下所示: <起始地址> <結(jié)束地址> ...
    深圳陽(yáng)光閱讀 12,192評(píng)論 28 5
  • css3新增了一個(gè)好玩的屬性:animation,雖然用它做出來(lái)的動(dòng)畫并沒(méi)有多么炫酷流暢忍疾,但是它減少了代碼量并且在...
    sakatayui醬閱讀 10,216評(píng)論 0 2