之前博客介绍啦一种异常捕获后弹窗提示用户的方法,《iOS崩溃 捕获异常处理》,下面提供另外一种异常捕获的方法。原理一致,但实现略有不同。可供参考。
1、在didFinishLaunchingWithOptions 中,注册消息处理函数,处理崩溃信息,写入本地。
//注册消息处理函数的处理方法,处理崩溃信息,写入本地
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
2、将CrashManager.h、 CrashManager.m 拖拽到工程中,具体实现如下:
CrashManager.h:
@interface CrashManager : NSObject
/** 捕捉Crash */
void uncaughtExceptionHandler(NSException *exception);
+ (id)defaultManager;//单例
/** 移除Crash的log日志 */
- (void)clearCrashLog;
/** 是否有log日志 */
- (BOOL)isCrashLog;
/** crash log日志 */
- (NSString *)crashLogContent;
@end
CrashManager.m 中核心函数如下:
void uncaughtExceptionHandler(NSException *exception){
// 异常的堆栈信息
NSArray *stackArray = [exception callStackSymbols];
// 出现异常的原因
NSString *reason = [exception reason];
// 异常名称
NSString *name = [exception name];
NSString *exceptionInfo = [NSString stringWithFormat:@"Exception reason:%@\nException name:%@\nException stack:%@",name, reason, stackArray];
NSLog(@"%@", exceptionInfo);
NSMutableArray *tmpArr = [NSMutableArray arrayWithArray:stackArray];
[tmpArr insertObject:reason atIndex:0];
NSString *crashLocalPath = [NSString stringWithFormat:@"%@/Documents/microFinanceCrashError.txt",NSHomeDirectory()];
NSLog(@"crash LocalPath :%@ ",crashLocalPath);
//保存到本地 -- 当然你可以在下次启动的时候,上传这个log
[exceptionInfo writeToFile:crashLocalPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
+ (id)defaultManager{
@synchronized(self){
static dispatch_once_t pred;
dispatch_once(&pred, ^{
crashManager = [[self alloc] init];
});
}
return crashManager;
}
#pragma mark -移除Crash的log日志
- (void)clearCrashLog{
NSFileManager *fileManager = [[NSFileManager alloc]init];
[fileManager removeItemAtPath:LocalCrashLogPath error:nil];
}
#pragma mark - 是否有log日志
- (BOOL)isCrashLog{
NSError *error;
NSString *textFileContents = [NSString stringWithContentsOfFile:LocalCrashLogPath encoding:NSUTF8StringEncoding error:&error];
if ([self checkConvertNull:textFileContents]) {//无log日志
return NO;
}else{
return YES;
}
}
#pragma mark -crash log日志
- (NSString *)crashLogContent{
NSError *error;
NSString *textFileContents = [NSString stringWithContentsOfFile:LocalCrashLogPath encoding:NSUTF8StringEncoding error:&error];
if ([self checkConvertNull:textFileContents]) {//无log日志
return @"";
}else{
return textFileContents;
}
}
#pragma mark - 检查是否有空字符
- (BOOL)checkConvertNull:(NSString *)object{
if ([object isEqual:[NSNull null]] || [object isKindOfClass:[NSNull class]] ||object==nil || [object isEqualToString:@""]) {
return YES;
}else{
return NO;
}
}
3、在ViewController中,做如下测试案例:
- (void)viewDidLoad {
[super viewDidLoad];
CrashManager *crashManager = [CrashManager defaultManager];
if ([crashManager isCrashLog]) {//Crash日志
NSString *crashString = [crashManager crashLogContent];//Crash日志内容
NSLog(@"crashString = %@",crashString);//
}
// [crashManager clearCrashLog];//清除Crash日志
//Crash测试
UIButton *crashBtn = [UIButton buttonWithType:UIButtonTypeCustom];
crashBtn.frame = CGRectMake(self.view.frame.size.width/2 - 50, 200, 100, 40);
crashBtn.backgroundColor = [UIColor redColor];
[crashBtn addTarget:self action:@selector(crashTest) forControlEvents:UIControlEventTouchUpInside];
[crashBtn setTitle:@"Crash" forState:UIControlStateNormal];
[crashBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self.view addSubview:crashBtn];
}
-(void)crashTest{
NSString *crashString = nil;
NSDictionary *params = [NSDictionary dictionary];
params = @{@"crashTest":crashString,
};
}