iOS崩溃 捕获异常处理(二)

之前博客介绍啦一种异常捕获后弹窗提示用户的方法,《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,
               };
}

Demo地址:https://github.com/heroBlog/CrashManager

你可能感兴趣的:(开发纪录)