Crash我們不得不面對的問題,但是好多人在遇到Crash的時候都無從下手,很多的時候都是憑著感覺找問題。今天我做了5篇文章來幫助我們更加清晰的認清iOS中的Crash
想要了解更詳細的內(nèi)容可以點擊這里

上面這張圖想必大家都不陌生吧
其實控制臺輸出的日志信息就是NSException產(chǎn)生的,一旦程序拋出異常,程序就會崩潰,控制臺就會有這些崩潰日志。
這個類是專門表示異常的,Cocoa框架要求所有的異常都是它或者是它子類的實例,當(dāng)實例調(diào)用raise或者throw方法時就會出現(xiàn)我們?nèi)缟蠄D之類的崩潰,并給出它的一些相關(guān)信息。下面介紹NSException對象的幾個重要的屬性。
- name : 用于唯一地識別異常的短字符串。名稱是必需的
- reason:一個更長的包含造成異常原因的“人類可讀的”字符串。原因是必需的。
- userInfo:主要當(dāng)異常被拋出時,返回原因等信息的一個字典。
異常處理

上面這幅圖是官網(wǎng)給出的一個圖
- @try - 定義一個代碼塊,它是一個異常處理域:可能引發(fā)異常的代碼。
- @catch()- 定義一個包含代碼的塊,用于處理塊中拋出的異常@try。參數(shù)@catch是本地拋出的異常對象; 這通常是一個NSException對象,但也可以是其他類型的對象,例如NSString對象。
- @finally - 定義一個相關(guān)代碼塊,無論是否拋出異常,隨后都會執(zhí)行該代碼塊。
- @throw - 拋出異常; 這個指令的行為幾乎與raise方法相同NSException。您通常會拋出NSException對象
最簡單的使用
//異常的名稱
NSString *exceptionName = @"異常的名稱";
//異常的原因
NSString *exceptionReason = @"我異常的原因";
//異常的信息
NSDictionary *exceptionUserInfo = nil;
NSException *exception = [NSException exceptionWithName:exceptionName reason:exceptionReason userInfo:exceptionUserInfo];
NSString *test = @"test";
if ([test isEqualToString:@"test"]) {
//拋異常
@throw exception;
}

系統(tǒng)也給我們提供了很多種異??梢灾苯邮褂?/p>
//系統(tǒng)提供了很多異??梢灾苯邮褂?FOUNDATION_EXPORT NSString * const NSGenericException;
FOUNDATION_EXPORT NSString * const NSRangeException;
FOUNDATION_EXPORT NSString * const NSInvalidArgumentException;
FOUNDATION_EXPORT NSString * const NSInternalInconsistencyException;
FOUNDATION_EXPORT NSString * const NSMallocException;
FOUNDATION_EXPORT NSString * const NSObjectInaccessibleException;
FOUNDATION_EXPORT NSString * const NSObjectNotAvailableException;
FOUNDATION_EXPORT NSString * const NSDestinationInvalidException;
FOUNDATION_EXPORT NSString * const NSPortTimeoutException;
FOUNDATION_EXPORT NSString * const NSInvalidSendPortException;
FOUNDATION_EXPORT NSString * const NSInvalidReceivePortException;
FOUNDATION_EXPORT NSString * const NSPortSendException;
FOUNDATION_EXPORT NSString * const NSPortReceiveException;
FOUNDATION_EXPORT NSString * const NSOldStyleException;
用途
- 1、可以用來捕獲異常,防止程序的崩潰。當(dāng)你意識到某段代碼可能存在崩潰的危險,那么你就可以通過捕獲異常來防止程序的崩潰
- 2、分類(category) + runtime + 異常的捕獲 來防止Foundation一些常用方法使用不當(dāng)而導(dǎo)致的崩潰。其原理就是利用category、runtime來交換兩個方法,并且在方法中捕獲異常進行相應(yīng)的處理
數(shù)組越界這是一個十分常見的問題,這里我們就來簡單的解決一下數(shù)組越界問題
NSMutableArray *arr = [NSMutableArray arrayWithObject:@[@"1"]];
NSLog(@"%@",arr[2]);
NSLog(@"%s",__func__);
上面的代碼肯定會出現(xiàn)下面這個錯誤

但是我們可以在數(shù)組越界的時候進行一個NSException處理,那么我們的程序就不會閃退
#import "NSMutableArray+Extension.h"
#import <objc/runtime.h>
@implementation NSMutableArray (Extension)
+ (void)load {
Class arrayMClass = NSClassFromString(@"__NSArrayM");
//獲取系統(tǒng)的添加元素的方法
Method addObject = class_getInstanceMethod(arrayMClass, @selector(objectAtIndexedSubscript:));
//獲取我們自定義添加元素的方法
Method avoidCrash = class_getInstanceMethod(arrayMClass, @selector(avoidCrashobjectAtIndexedSubscript:));
method_exchangeImplementations(addObject, avoidCrash);
}
- (id)avoidCrashobjectAtIndexedSubscript:(NSUInteger)idx {
@try {
return [self avoidCrashobjectAtIndexedSubscript:idx];
}
@catch (NSException *exception) {
//你可以在這里進行相應(yīng)的操作處理
NSLog(@"這里數(shù)組越界");
NSLog(@"異常名稱:%@ 異常原因:%@",exception.name, exception.reason);
}
@finally {
}
}
@end

我們可以根據(jù)NSException的特性寫一些簡單的防止崩潰的框架。
NSError
每個程序都必須處理運行時發(fā)生的錯誤。例如,程序可能無法打開文件,或者可能無法解析XML文檔。通常這些錯誤需要程序通知用戶它們。 在程序中我們可以通過NSError把導(dǎo)致錯誤的原因回調(diào)給調(diào)用者
NSError對象里封裝了三條信息:
1、Error domain:錯誤范圍,其類型為字符串
錯誤發(fā)生的范圍,也就是產(chǎn)生錯誤的根源,通常用一個特有的全局變量來定義。比方說,“處理URL的子系統(tǒng)”在從URL中解析或者取得數(shù)據(jù)時如果出錯了,那么就會使用NSURLErrorDomain來表示錯誤范圍。2、Error code:錯誤碼,其類型為整數(shù)
獨有的錯誤代碼,用以指明在某個范圍內(nèi)具體發(fā)生了何種錯誤。某個特定的范圍內(nèi)可能會發(fā)生一系列相關(guān)錯誤,這些錯誤情況通常采用enum來定義。例如當(dāng)http請求出錯時,可能會把http狀態(tài)碼設(shè)為錯誤碼。3、User info:用戶信息,其類型為字典
有關(guān)此錯誤的額外信息,其中或許包含一段“本地化的描述”,獲取還含有導(dǎo)致該錯誤發(fā)生的另外一個錯誤,經(jīng)由此種信息,可將相關(guān)錯誤串成一條“錯誤鏈”。
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:121 userInfo:@{NSLocalizedDescriptionKey:@"本地化的錯誤描述"}];
NSLog(@"error.userInfo:%@\nerror.code:%ld", error.userInfo,error.code);