hihi,勇敢的小伙伴儿们大家好, 了解这个是因为我在项目里集成了Bugly,即使不在开发过程,用户使用项目产生崩溃的时候也能将崩溃的原因上传到服务器上,尤其是试运营的版本,能够为后期优化App和减少Bug数提供不少方便,记得以前看安卓代码有try/catch的捕捉异常和处理异常的操作(此处存疑,记不太清了),想着iOS异常是怎么捕捉到的呢?于是有了这篇博客。
接下来跟大家一起学习一下NSSetUncaughtExceptionHandler这个类、顺便了解一下NSException的强大~
利用NSSetUncaughtExceptionHandler可以用来处理异常崩溃。崩溃报告系统会用NSSetUncaughtExceptionHandler方法设置全局的异常处理器。
如果自定义NSSetUncaughtExceptionHandler监听事件,会导致第三方监听(如Bugly)失效,需要注意。
#import "ViewController.h"
void UncaughtExceptionHandler(NSException *exception) {
NSArray *arr = [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSLog(@"\n%@\n%@\n%@",arr,reason,name);
}
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
NSArray *arr = @[@(0),@(1)];
NSLog(@"%@",arr[2]);//模拟越界异常
}
@end
运行结果:
参考文章:NSSetUncaughtExceptionHandler处理异常
NSException是什么?NSException是很多开发者最熟悉的陌生人,包括我在内,其实每天都跟它打过N次照面,可是仅仅是认识而已,基本不清楚它的内涵···
就像前面我们自定义输入的Exception的name reason和stack symbols,然而控制台经常输出的日志信息就是NSException产生的默认格式,一旦程序抛出异常,程序就会崩溃,控制台就会有这些崩溃日志。
1.自定义异常崩溃
//创建异常
NSString *exceptionName = @"hi,我是一个异常";
NSString *excaptionReason = @"我不开心了,所以我要让程序崩溃";
NSDictionary *exceptionUserInfo = nil;
NSException *exception = [NSException exceptionWithName:exceptionName reason:excaptionReason userInfo:exceptionUserInfo];
//抛出异常
@throw exception;
运行结果:
2.异常的简单处理
NSMutableArray *array = [NSMutableArray array];
NSString *nilStr = nil;
@try {
//有可能出现异常的代码,这里写的代码一定会出现问题
[array insertObject:nilStr atIndex:0];
} @catch(NSException *exception) {
//如果@try的代码出现异常,就会执行这里的代码,也就可以在这里进行相应的操作
NSLog(@"%@",exception.reason);
//如果想要抛出异常就执行如下代码,程序就会崩溃,便于调试
//@throw exception;
} @finally {
//这里的代码一定会执行
NSLog(@"已成功处理异常");
}
运行结果:
3.防止潜在的崩溃风险
如果你并不知道程序运行到那里会出现异常,或者说对于Foundation框架里有非常多常用的方法有导致崩溃的潜在危险,那么该如何拦截潜在的异常风险,并进行相应的处理,防止崩溃的出现呢?
解决办法是:
我们以“在数组中插入一个空对象”的崩溃异常为例,进行相应的处理。
首先给NSMutableArray加一个名为Extension的Category
NSMutableArray+Extension.m
#import "NSMutableArray+Extension.h"
#import
@implementation NSMutableArray (Extension)
+ (void)load {
Class arrayMClass = NSClassFromString(@"__NSArrayM");
//获取系统的添加元素的方法
Method addObject = class_getInstanceMethod(arrayMClass, @selector(addObject:));
//获取我们自定义添加元素的方法
Method avoidCrashAddObject = class_getInstanceMethod(arrayMClass, @selector(avoidCrashAddObject:));
//将两个方法进行交换
//当你调用addObject的时候,其实就是调用avoidCrashAddObject
//当你调用avoidCrashAddObject的时候,其实就是调用addObject
method_exchangeImplementations(addObject, avoidCrashAddObject);
}
- (void)avoidCrashAddObject:(id)object {
@try {
//可能出现异常的方法 比如数组不能添加空对象 所以addObject可能会出现异常
[self avoidCrashAddObject:object];//本质是调用addObject
} @catch (NSException *exception) {
//捕捉到异常后对该异常进行处理
NSLog(@"\n异常名称:%@\n异常原因:%@",exception.name,exception.reason);
} @finally {
//这里的代码一定会执行,可以进行相应的操作
}
}
@end
然后在ViewController.m中测试一下
NSMutableArray *array = [[NSMutableArray alloc] init];
NSString *nilStr = nil;
//测试异常是否执行
[array addObject:nilStr];
运行结果:
程序没有崩溃,即没有抛出异常,继续运行了下去,并按照我们自定义的方法输出了异常名称及其原因。
有效的规避了数组插入空对象的异常崩溃,为程序稳定性做出了巨大贡献。✿✿ヽ(°▽°)ノ✿
关于这个的Demo放在我的github自定义异常处理上。
我已经在文章里将代码写的很全了,应该用不到,不过大家需要的话可以下载~
今日写完这篇博客有些疲累,有大神已经把常见崩溃处理了,我还没有学习,故此先送上原文地址给各位小伙伴儿
iOS runtime实用篇--和常见崩溃say good-bye!欢迎大家跟我一起探讨~
有问题烦请联系我,多谢!