前言
崩潰是讓發(fā)人員比較頭痛的事情,app崩潰了,說明代碼寫的有問題叼风,這時(shí)如何快速定位到崩潰的地方很重要。調(diào)試階段是比較容易找到出問題的地方的棍苹,但是已經(jīng)上線的app并分析崩潰報(bào)告就比較麻煩了无宿。最終,我們可以通過iOS崩潰日志在大多數(shù)情況下枢里,你能從中了解到關(guān)于閃退的詳盡孽鸡、有用的信息。線上崩潰可以通過 iTunesConnect 中心的Cash收集栏豺,也可以通過第三方Cash收集工具彬碱,亦或自己在工程中手動(dòng)收集崩潰日志上傳到服務(wù)器中,本文做個(gè)小結(jié)奥洼,希望對(duì)初入者能有些幫助巷疼。
崩潰
崩潰是由于程序拋出異常,系統(tǒng)異常結(jié)束的一種現(xiàn)象灵奖。我們可以先了解一下異常 NSException嚼沿,這對(duì)于我們理解崩潰有幫助。NSException掌控著程序的生命瓷患,程序的崩潰就是NSException來控制的骡尽。其實(shí)主要的出發(fā)點(diǎn)是讓開發(fā)者認(rèn)識(shí)到哪里的代碼有問題。
** NSException**
其實(shí)控制臺(tái)輸出的日志信息就是NSException產(chǎn)生的擅编,一旦程序拋出異常爆阶,程序就會(huì)崩潰,控制臺(tái)就會(huì)有這些崩潰日志沙咏。
下面代碼就會(huì)讓你的程序崩潰(下面代碼出自別人的文章辨图,文末有原文出處)
//異常的名稱
NSString *exceptionName = @"自定義異常";
//異常的原因
NSString *exceptionReason = @"我長得太帥了,所以程序崩潰了";
//異常的信息
NSDictionary *exceptionUserInfo = nil;
NSException *exception = [NSException exceptionWithName:exceptionName reason:exceptionReason userInfo:exceptionUserInfo];
NSString *aboutMe = @"太帥了";
if ([aboutMe isEqualToString:@"太帥了"])
{ //拋異常
@throw exception;
}
崩潰截圖如下
NSException的實(shí)用技巧
1肢藐、 若自己封裝一套SDK故河,若要提示哪里出錯(cuò),那么就可以使用NSException吆豹。就像上面NSException的基本用法中的代碼一樣鱼的。
-
2理盆、可以用來捕獲異常,防止程序的崩潰凑阶。當(dāng)你意識(shí)到某段代碼可能存在崩潰的危險(xiǎn)猿规,那么你就可以通過捕獲異常來防止程序的崩潰。代碼如下
@try { //如果@try中的代碼會(huì)導(dǎo)致程序崩潰宙橱,就會(huì)來到@catch //將一個(gè)nil插入到可變數(shù)組中姨俩,這行代碼肯定有問題 [arrayM addObject:nilStr]; } @catch (NSException *exception) { //如果@try中的代碼有問題(導(dǎo)致崩潰),就會(huì)來到@catch //在這里你可以進(jìn)行相應(yīng)的處理操作 //如果你要拋出異常(讓程序崩潰),就寫上 @throw exception } @finally { //@finally中的代碼是一定會(huì)執(zhí)行的 //你可以在這里進(jìn)行一些相應(yīng)的操作 }
崩潰日志
關(guān)于修復(fù)崩潰的Bug,如果你憑借自己的經(jīng)驗(yàn)师郑,有時(shí)候可能會(huì)遇到問題卡住环葵,我想最快的方式就是通過分析崩潰日志來解決崩潰。
什么是崩潰日志宝冕,從哪里能得它
iOS設(shè)備上的應(yīng)用閃退時(shí)张遭,操作系統(tǒng)會(huì)生成一個(gè)崩潰報(bào)告,也叫崩潰日志地梨,保存在設(shè)備上菊卷。
崩潰日志上有很多有用的信息,包括應(yīng)用是什么情況下閃退的宝剖。通常洁闰,上面有每個(gè)正在執(zhí)行線程的完整堆棧跟蹤信息,所以你能從中了解到閃退發(fā)生時(shí)各線程都在做什么诈闺,并分辨出閃退發(fā)生在哪個(gè)線程上渴庆。
有幾種方法可以從設(shè)備上獲取崩潰日志铃芦。
-
xcode中查看崩潰信息
xcode->Window->Organizer->Crashes
-
通過Xcode查看設(shè)備崩潰信息
除了上面的系統(tǒng)分析工具來進(jìn)行分析雅镊,如果是我們自己直接使用手機(jī)連接崩潰或者崩潰之后連接手機(jī),選擇window-> devices -> 選擇自己的手機(jī) -> view device logs 就可以查看我們的崩潰信息了刃滓。
-
使用第三方軟件:itools等
如果你平時(shí)不用iTunes仁烹,而是使用itools這類第三方的軟件對(duì)iPhone設(shè)備進(jìn)行管理,也是沒問題的咧虎。
打開itools卓缰,在你的設(shè)備下,找到“高級(jí)功能”砰诵,點(diǎn)擊“崩潰日志”征唬,然后將需要的日志導(dǎo)出到電腦里面就可以了! 應(yīng)用提交到App Store后茁彭,你也能從 iTunes Connect 獲取到用戶的崩潰日志. 登錄到 iTunes Connect 上, 選擇 Manage Your Applications, 點(diǎn)擊相應(yīng)的應(yīng)用, 點(diǎn)擊應(yīng)用圖標(biāo)下面的 View Details 按鈕, 然后點(diǎn)擊右欄Links部分的 Crash Reports 总寒。
什么時(shí)候不會(huì)產(chǎn)生崩潰日志
以下情況不會(huì)有崩潰信息產(chǎn)生:
- 內(nèi)存訪問錯(cuò)誤(不是野指針錯(cuò)誤)
- 低內(nèi)存,當(dāng)程序內(nèi)存使用過多會(huì)造成系統(tǒng)低內(nèi)存的問題理肺,系統(tǒng)會(huì)將程序內(nèi)存回收
- 因?yàn)槟撤N原因觸發(fā)看門狗機(jī)制
一般Xcode不輸出Crash日志有一下幾個(gè)可能:
NSSetUncaughtExceptionHandler() 可能被重寫了,(比如你引用了一些第三方庫, 它的SDK里面可能包含了把Crash的日志上傳到服務(wù)器, 這樣這個(gè)日志可能被重寫了, 就不打印本地的崩潰信息了) 盡量把它放在didFinishLaunchingWithOptions 最后面的一行代碼塊里.
還一種崩潰的情況是 EXC_BAD_ACCESS 摄闸,EXC_BAD_ACCESS異常的本意是指訪問不到內(nèi)存中這個(gè)地址的值善镰,可能是由于些變量已經(jīng)被回收了,亦可能是由于使用棧內(nèi)存的基本類型的數(shù)據(jù)賦值給了id類型的變量年枕。當(dāng)遇到這種錯(cuò)誤, 控制一般不會(huì)給你很多關(guān)于崩潰的信息, 這種崩潰你開啟僵尸對(duì)象模式即可, 不過記住你在正式發(fā)布的時(shí)候記得把這個(gè)勾取消, 不然會(huì)造成內(nèi)存泄漏炫欺。*
解析崩潰日志
.dSYM 文件
.dSYM 文件稱為符號(hào)表,是指在Xcode項(xiàng)目編譯后熏兄,在編譯生成的二進(jìn)制文件.app的同級(jí)目錄下生成的同名的.dSYM文件品洛。
.dSYM文件其實(shí)是一個(gè)目錄,在子目錄中包含了一個(gè)16進(jìn)制的保存函數(shù)地址映射信息的中轉(zhuǎn)文件霍弹,所有Debug的symbols都在這個(gè)文件中(包括文件名毫别、函數(shù)名、行號(hào)等)典格,所以也稱之為調(diào)試符號(hào)信息文件岛宦。符號(hào)表就是用來符號(hào)化 crash log(崩潰日志)。crash log中有一些方法16進(jìn)制的內(nèi)存地址等耍缴,通過符號(hào)表就能找到對(duì)應(yīng)的能夠直觀看到的方法名之類砾肺。
符號(hào)集是我們對(duì)ipa文件進(jìn)行打包之后,和.app文件同級(jí)的后綴名為.dSYM的文件防嗡,這個(gè)文件必須使用Xcode進(jìn)行打包才有变汪。每一個(gè).dSYM文件都有一個(gè)UUID,和.app文件中的UUID對(duì)應(yīng)蚁趁,代表著是一個(gè)應(yīng)用裙盾。而.dSYM文件中每一條崩潰信息也有一個(gè)單獨(dú)的UUID,用來和程序的UUID進(jìn)行校對(duì)他嫡。這些UUID一致時(shí)才可以解析出當(dāng)前APP的崩潰信息.
我們在Archive的時(shí)候會(huì)生成.xcarchive文件番官,然后顯示包內(nèi)容就能夠在里面找到.dsYM文件和.app文件。
所以 為了更好的分析崩潰原因钢属,在每次上架APP的時(shí)候徘熔,應(yīng)該保留對(duì)應(yīng)的app文件和dsym文件。
當(dāng)獲得一份crash日志時(shí)淆党,我們需要將初始展示的十六進(jìn)制地址等原始信息映射為源代碼級(jí)別的方法名稱和代碼行數(shù)酷师,使其對(duì)開發(fā)人員可讀。這個(gè)過程稱為符號(hào)化解析染乌。要成功地符號(hào)化解析一份crash日志山孔,我們需要有對(duì)應(yīng)的應(yīng)用程序二進(jìn)制文件以及符號(hào)(.dSYM)文件。
當(dāng)程序崩潰的時(shí)候荷憋,我們可以獲得到崩潰的錯(cuò)誤堆棧台颠,但是這個(gè)錯(cuò)誤堆棧都是0x開頭的16進(jìn)制地址,需要我們使用Xcode自帶的symbolicatecrash工具來將.Crash和.dSYM文件進(jìn)行符號(hào)化台谊,就可以得到詳細(xì)崩潰的信息蓉媳。
Symbolicatecrash
Symbolicatecrash是Xcode自帶的一個(gè)分析工具譬挚,可以通過機(jī)器上的崩潰日志和應(yīng)用的.dSYM文件定位發(fā)生崩潰的位置,把crash日志中的地址替換成代碼相應(yīng)位置酪呻。
使用效果:
分析前:
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 CoreFoundation 0x3723b870 0x37180000 + 768112
1 CoreFoundation 0x37196648 0x37180000 + 91720
2 CoreFoundation 0x37181e90 0x37180000 + 7824
3 CoreFoundation 0x3718bb74 0x37180000 + 47988
4 CoreFoundation 0x3718ba8e 0x37180000 + 47758
5 UIKit 0x30f0f866 0x30f0a000 + 22630
分析后:
0 CoreFoundation 0x3723b870 ___forwarding___ + 136
1 CoreFoundation 0x37196648 _CF_forwarding_prep_0 + 40
2 CoreFoundation 0x37181e90 CFRetain + 76
3 CoreFoundation 0x3718bb74 +[__NSArrayI __new::] + 48
4 CoreFoundation 0x3718ba8e -[__NSPlaceholderArray initWithObjects:count:] + 294
5 UIKit 0x30f0f866 -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 70
在這個(gè)路徑下你可以得到系統(tǒng)自帶的Symbolicatecrash减宣,把它拷貝到指定的文件下
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources
獲取.dSYM文件
選中archive的版本右擊,選擇Show in Finder就可以選中archived 文件然后顯示包內(nèi)容玩荠,就可以找到dSYM文件了漆腌。
解析步驟
- 我在解析崩潰信息的時(shí)候,首先在桌面上建立一個(gè)Crash文件夾阶冈,然后將.Crash闷尿、app、.dSYM女坑、symbolicatecrash放在這個(gè)文件夾中填具。
注意:這里的 .crash 必須是真機(jī)安裝的打包的那個(gè) sometwo 產(chǎn)生的崩潰日志才行,運(yùn)行其他的版本產(chǎn)生的崩潰日志匆骗,以下的解析會(huì)失敗劳景。
如何把這個(gè)打包的應(yīng)用安裝到測試機(jī)上呢?注意這里的應(yīng)用不是 ipa文件碉就,而且這個(gè)手機(jī)也可以沒被加入到當(dāng)前的開發(fā)者賬號(hào)中盟广。
手機(jī)連上 itunes,在itunes中打開 手機(jī)的應(yīng)用瓮钥, 文件->添加到資料庫 把桌面是上的那個(gè)應(yīng)用添加進(jìn)入筋量,再同步更新到測試機(jī)器中即可。
如果你一直解析失敗碉熄,那么可能你的 .Crash桨武、app、.dSYM具被、的UUID不一致玻募,通過終端工具可以查看 app只损、 .dSYM文件的UUID:
cd到文件夾
dwarfdump --uuid Sometwo.app/Sometwo
dwarfdump --uuid Sometwo.app.dSYM
三者一致才能還原符號(hào)表一姿。
由上圖可以看出三折的UUID是不一致的,所以會(huì)一直解析失敗跃惫,無法符號(hào)化 .Crash文件叮叹。
在終端中輸入以下命令, iOS002 換成你自己的用戶名稱
- cd /Users/iOS002/Desktop/Cash/
- export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"
- ./symbolicatecrash /Users/iOS002/Desktop/Cash/SomeTwo.crash /Users/iOS002/Desktop/Cash/SomeTwo.app.dSYM > Control_symbol.crash
一切正常的話這樣就完成了一個(gè)崩潰日志的解析工作爆存。解析完成后會(huì)生成一個(gè)新的.Crash文件蛉顽,這個(gè)文件中就是崩潰詳細(xì)信息。圖中紅色標(biāo)注的部分就是我們代碼崩潰的部分先较。
收集崩潰日志
獲取崩潰信息方式
在iOS中獲取崩潰信息的方式有很多携冤,比較常見的是使用友盟悼粮、云測、百度曾棕、Crashlytics等第三方分析工具扣猫,或者自己收集崩潰信息并上傳公司服務(wù)器。下面列舉一些我們常用的崩潰分析方式:
- 自己實(shí)現(xiàn)應(yīng)用內(nèi)崩潰收集翘地,并上傳服務(wù)器申尤。
- 使用友盟、云測衙耕、百度昧穿、Crashlytics等第三方崩潰統(tǒng)計(jì)工具。
自己收集崩潰信息
蘋果給我們提供了異常處理的類橙喘,NSException類时鸵。這個(gè)類可以創(chuàng)建一個(gè)異常對(duì)象,也可以通過這個(gè)類獲取一個(gè)異常對(duì)象厅瞎。這個(gè)類中我們最常用的還是一個(gè)獲取崩潰信息的C函數(shù)寥枝,我們可以通過這個(gè)函數(shù)在程序發(fā)生異常的時(shí)候收集這個(gè)異常。然后把收集到的崩潰信息發(fā)送到自己的服務(wù)器磁奖。
我們也可以通過下面方法獲取崩潰統(tǒng)計(jì)的函數(shù)指針:
NSUncaughtExceptionHandler *handler = NSGetUncaughtExceptionHandler();
NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);
// 收集崩潰信息的調(diào)用方法
void UncaughtExceptionHandler(NSException *exception) {
NSArray *arr = [exceptioncallStackSymbols];//得到當(dāng)前調(diào)用棧信息
NSString *reason = [exceptionreason];//非常重要囊拜,就是崩潰的原因
NSString *name = [exceptionname];//異常類型
NSLog(@"exception type : %@ \n crash reason : %@ \n call stack info : %@", name, reason, arr);
}
獲取到了崩潰的發(fā)送給開發(fā)者有以下兩種方式:
將崩潰信息持久化在本地,下次程序啟動(dòng)時(shí)比搭,將崩潰信息作為日志發(fā)送給開發(fā)者冠跷。
-
通過郵件發(fā)送給開發(fā)者。不過此種方式需要得到用戶的許可身诺,因?yàn)閕OS不能后臺(tái)發(fā)送短信或者郵件蜜托,會(huì)彈出發(fā)送郵件的界面,只有用戶點(diǎn)擊了發(fā)送才可發(fā)送霉赡。不過橄务,此種方式最符合蘋果的以用戶至上的原則。
發(fā)送郵件代碼: NSString *crashLogInfo = [NSString stringWithFormat:@"exception type : %@ \n crash reason : %@ \n callstack info : %@", name, reason, arr]; NSString*urlStr = [NSString stringWithFormat:@"mailto://tianranwuwai@yeah.net?subject=bug報(bào)告&body=感謝您的配合! 錯(cuò)誤詳情:%@",crashLogInfo]; NSURL *url =[NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; [[UIApplication sharedApplication] openURL:url];
我們是否也可以在程序崩潰時(shí)穴亏,將崩潰信息寫入本地蜂挪,APP再次啟動(dòng)時(shí),將崩潰信息上傳到我們的服務(wù)器嗓化。這里就要用到apple的一個(gè)函數(shù):NSSetUncaughtExceptionHandler棠涮。上代碼:
application didFinishLaunchingWithOptions中調(diào)用
[self catchCrashLogs];
- (void)catchCrashLogs{
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
}
void UncaughtExceptionHandler(NSException *exception){
if (exception ==nil)return;
NSArray *array = [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSDictionary *dict = @{@"appException":@{@"exceptioncallStachSymbols":array,@"exceptionreason":reason,@"exceptionname":name}};
if([SDFileToolClass writeCrashFileOnDocumentsException:dict]){
NSLog(@"Crash logs write ok!");
}
}
//寫入緩存中: 以下提供三個(gè)API,分別是:寫入刺覆,獲取严肪,清空
NSString * const SDCrashFileDirectory = @"SDMapHomeCrashFileDirectory"; //你的項(xiàng)目中自定義文件夾名
+ (NSString *)sd_getCachesPath{
return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
}
+ (BOOL)writeCrashFileOnDocumentsException:(NSDictionary *)exception{
NSString *time = [[NSDate date] formattedDateWithFormat:@"yyyyMMddHHmmss" locale:[NSLocale currentLocale]];
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *crashname = [NSString stringWithFormat:@"%@_%@Crashlog.plist",time,infoDictionary[@"CFBundleName"]];
NSString *crashPath = [[self sd_getCachesPath] stringByAppendingPathComponent:SDCrashFileDirectory];
NSFileManager *manager = [NSFileManager defaultManager];
//設(shè)備信息
NSMutableDictionary *deviceInfos = [NSMutableDictionary dictionary];
[deviceInfos setObject:[infoDictionary objectForKey:@"DTPlatformVersion"] forKey:@"DTPlatformVersion"];
[deviceInfos setObject:[infoDictionary objectForKey:@"CFBundleShortVersionString"] forKey:@"CFBundleShortVersionString"];
[deviceInfos setObject:[infoDictionary objectForKey:@"UIRequiredDeviceCapabilities"] forKey:@"UIRequiredDeviceCapabilities"];
BOOL isSuccess = [manager createDirectoryAtPath:crashPath withIntermediateDirectories:YES attributes:nil error:nil];
if (isSuccess) {
NSLog(@"文件夾創(chuàng)建成功");
NSString *filepath = [crashPath stringByAppendingPathComponent:crashname];
NSMutableDictionary *logs = [NSMutableDictionary dictionaryWithContentsOfFile:filepath];
if (!logs) {
logs = [[NSMutableDictionary alloc] init];
}
//日志信息
NSDictionary *infos = @{@"Exception":exception,@"DeviceInfo":deviceInfos};
[logs setObject:infos forKey:[NSString stringWithFormat:@"%@_crashLogs",infoDictionary[@"CFBundleName"]]];
BOOL writeOK = [logs writeToFile:filepath atomically:YES];
NSLog(@"write result = %d,filePath = %@",writeOK,filepath);
return writeOK;
}else{
return NO;
}
}
+ (nullable NSArray *)sd_getCrashLogs{
NSString *crashPath = [[self sd_getCachesPath] stringByAppendingPathComponent:SDCrashFileDirectory];
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *array = [manager contentsOfDirectoryAtPath:crashPath error:nil];
NSMutableArray *result = [NSMutableArray array];
if (array.count == 0) return nil;
for (NSString *name in array) {
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:[crashPath stringByAppendingPathComponent:name]];
[result addObject:dict];
}
return result;
}
+ (BOOL)sd_clearCrashLogs{
NSString *crashPath = [[self sd_getCachesPath] stringByAppendingPathComponent:SDCrashFileDirectory];
NSFileManager *manager = [NSFileManager defaultManager];
if (![manager fileExistsAtPath:crashPath]) return YES; //如果不存在,則默認(rèn)為刪除成功
NSArray *contents = [manager contentsOfDirectoryAtPath:crashPath error:NULL];
if (contents.count == 0) return YES;
NSEnumerator *enums = [contents objectEnumerator];
NSString *filename;
BOOL success = YES;
while (filename = [enums nextObject]) {
if(![manager removeItemAtPath:[crashPath stringByAppendingPathComponent:filename] error:NULL]){
success = NO;
break;
}
}
return success;
}
使用工具Crashlytics統(tǒng)計(jì)Crash
市場上有多種移動(dòng)應(yīng)用Crash收集工具, 如友盟,MTJ等驳糯。在iOS中篇梭, 收集Crash主要通過兩種方式, 一種是信號(hào)量機(jī)制酝枢,因?yàn)閏rash通常會(huì)發(fā)出信號(hào)量很洋,標(biāo)明某某應(yīng)用崩潰了, 另一種方式是每一個(gè)應(yīng)用都有一個(gè)crash handle, 即崩潰鉤子隧枫, 每當(dāng)程序崩潰時(shí)喉磁, 都會(huì)執(zhí)行這個(gè)回調(diào)。信號(hào)量比起崩潰句柄的區(qū)別有點(diǎn)像ios開發(fā)中的通知和delegate官脓。 信號(hào)量拋出后协怒,可以被多個(gè)捕獲crash的工具獲取到,然后取當(dāng)前的堆棧信息卑笨, 再利用該堆棧信息與原app的dsym文件進(jìn)行比對(duì)孕暇, 就可以找到崩潰的代碼行。
理論上講赤兴, 這個(gè)信號(hào)量機(jī)制優(yōu)秀于crash句柄妖滔, 因?yàn)檫@樣的話,可以有多個(gè)收集工具并行收集桶良, 前提是座舍,每個(gè)收集工具收集后,繼續(xù)拋出這個(gè)異常陨帆,而不是截?cái)噙@個(gè)異常曲秉,當(dāng)截?cái)嗪蠛罄m(xù)的其它工具就收集不到這個(gè)異常了, 會(huì)導(dǎo)致其它工具收集不全的問題疲牵。 而友盟正是這樣做的.
利用crash 句柄這種方式使得crash信息只能被一個(gè)收集工具所收集到承二,因?yàn)榫浔挥幸粋€(gè)。如果一個(gè)應(yīng)用中有多個(gè)收集工具都設(shè)置了這個(gè)句柄纲爸, 這里就得看誰最后設(shè)置這個(gè)句柄亥鸠, 誰就有效。
上面是收集crash的方式說明识啦, 現(xiàn)在說說Crashlytics這個(gè)工具负蚊。 原理和上面的一樣。 不一樣的是袁滥, 這個(gè)工具被twitter收購盖桥, 既然有這么一根大樹灾螃, 那就保證了這個(gè)工具的穩(wěn)定性题翻。 所以建議使用, 目前是免費(fèi)的。
使用步驟基本上可以分為如下:
- 注冊嵌赠,
- 收到邀請(qǐng)信塑荒, 然后一步步按其說明完成注冊。
- 根據(jù)其提示姜挺,下載一個(gè)mac app配合進(jìn)行使用齿税。
- 當(dāng)有崩潰發(fā)生時(shí),會(huì)給注冊的郵件發(fā)送崩潰統(tǒng)計(jì)炊豪,方便查看凌箕。
在crash信息收集時(shí), 如果正在進(jìn)行debug調(diào)試词渤,是收集不到信息的牵舱。
使用Crashlytics的好處:
- Crashlytics不會(huì)漏掉任何應(yīng)用崩潰信息(就這兩個(gè)字讓我決定使用crashlytics)
- Crashlytics可以象Bug管理工具那樣,管理這些崩潰日志缺虐, 可以根據(jù)頻率及影響用戶量來自動(dòng)設(shè)置優(yōu)先級(jí)
- 可以每天和每周將崩潰信息匯總發(fā)送到郵箱中芜壁。
具體使用,可以參照這篇文章Crashlytics
小結(jié)
有關(guān)應(yīng)用Crash的處理工作任重而道遠(yuǎn)高氮,后續(xù)會(huì)持續(xù)更新慧妄,先寫這些吧。
本文參考文章:
關(guān)于崩潰日志解讀很詳細(xì)很棒的的一篇文章
iOS被開發(fā)者遺忘在角落的NSException-其實(shí)它很強(qiáng)大
iOS崩潰調(diào)試(收集不同用戶的崩潰信息)
模擬器打印不出來 malloc stock的信息剪芍,需要真機(jī)塞淹。
1.unrecognized seletor。錯(cuò)誤:這種情況很簡單罪裹,給一個(gè)對(duì)象發(fā)送了一條它不認(rèn)識(shí)的消息窖铡。比如說你的.h中聲明了某一個(gè)方法,但是.m中卻沒有實(shí)現(xiàn)坊谁,而且你沒有對(duì)異常消息處理(消息轉(zhuǎn)發(fā))就會(huì)造成這種現(xiàn)象费彼。解決辦法:首先排查自己的某一些方法是否實(shí)現(xiàn),其次看一下哪些對(duì)象接收了它不該接收的消息口芍。
2.index 1 beyond NSArraMu [0,0]數(shù)組越界:數(shù)組越界這個(gè)不多說箍铲。
3.NSNul length 這個(gè)異常以可以歸類為第一種,也是給某一個(gè)對(duì)象發(fā)送了不識(shí)別的消息鬓椭。常見原因有:給UILabel對(duì)象設(shè)置了text颠猴,此時(shí)的text內(nèi)容為空字符串null,然后你在取text的length的時(shí)候就會(huì)拋出異常小染。
4.EXC_BAD_ACCESS異常:這種大多數(shù)是對(duì)象提前釋放翘瓮,訪問了野指針的錯(cuò)誤。解決辦法:排查所有聲明為weak對(duì)象的使用裤翩,是否在沒有持有的情況下再次訪問了該對(duì)象(該對(duì)象已經(jīng)被釋放)资盅,第二在MRC情況下,排查一下所以已經(jīng)release的對(duì)象(聲明一點(diǎn),MRC中全局變量最好在dealloc方法中進(jìn)行釋放)呵扛,第三排查一下所有block每庆,是否block被正常賦值等。
5.崩潰在main函數(shù)今穿。這種情況最苦逼也是最難找到bug所在缤灵,這種情況下,用@try @catch將main函數(shù)包裹起來蓝晒,這樣會(huì)拋出異常堆棧信息等腮出,或者通過添加全局breakPoint來追蹤bug。(扯淡)
@try @catch 是最后的大招