iOS NSException异常处理

为什么使用NSException

在平常的开发过程中,由于代码不严谨或者没有对参数做校验处理会造成程序crash,所以需要去监控项目中的crash并及时解决。NSException是针对OC类异常捕获的一套机制。

如何使用NSException

NSException的结构如下:

@interface NSException : NSObject <NSCopying, NSSecureCoding> {
    @private
    NSString        *name;
    NSString        *reason;
    NSDictionary    *userInfo;
    id          reserved;
}

用法:

static NSUncaughtExceptionHandler* fb_previousUncaughtExceptionHandler;

void installUncaughtExceptionHandler(void){
    fb_previousUncaughtExceptionHandler = NSGetUncaughtExceptionHandler();
    NSSetUncaughtExceptionHandler(&uncaughtHandleException);
}
void uninstallUncaughtExceptionHandler(void){
    if(fb_previousUncaughtExceptionHandler){
        NSSetUncaughtExceptionHandler(fb_previousUncaughtExceptionHandler);
    }
}
void uncaughtHandleException(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);
    if (fb_previousUncaughtExceptionHandler != NULL)
    {
        fb_previousUncaughtExceptionHandler(exception);
    }
}

我们用NSMutableArray为例,添加一个空的object,看看会怎么样

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    installUncaughtExceptionHandler();

    NSMutableArray *array = [NSMutableArray array];
    NSString *nilStr = nil;
    [array addObject:nilStr];
   }

程序运行后会崩溃,通过断点可以看到捕获到的异常原因以及相关堆栈信息

image.png

如何避免潜在的crash

由于OC中很多崩溃都是来源于没有对入参进行判断,所以调用方法时对入参进行判断就能提前拦截崩溃。常见的处理方式有hook和安全接口两种,下面以hook为例。

#import "NSMutableArray+fbSafe.h"
#import <objc/runtime.h>

@implementation NSMutableArray (fbSafe)

+ (void)load {
    [self swizzMethodOriginalSelector:@selector(addObject:)
                     swizzledSelector:@selector(avoidCrashAddObject:)];
}

+ (void)swizzMethodOriginalSelector:(SEL)originalSelector
                   swizzledSelector:(SEL)swizzledSelector {
    //获取当前类
    Class arrayMClass = NSClassFromString(@"__NSArrayM");
    //获取系统的添加元素的方法
    Method originalMethod = class_getInstanceMethod(arrayMClass, originalSelector);
    //获取自定义添加元素的方法
    Method swizzledMethod = class_getInstanceMethod(arrayMClass, swizzledSelector);
    BOOL didAddMethod = class_addMethod(arrayMClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    //方法交换
    if (didAddMethod) {
        class_replaceMethod(arrayMClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
 
- (void)avoidCrashAddObject:(id)object {
 
    @try {
        //可能出现异常的方法 比如数组不能添加空对象 所以addObject可能会出现异常
        [self avoidCrashAddObject:object];//本质是调用addObject
    
    } @catch (NSException *exception) {
        //捕捉到异常后对该异常进行处理
        NSLog(@"\n异常名称:%@\n异常原因:%@ \n异常堆栈信息:%@",exception.name,exception.reason,exception.callStackSymbols);
    } @finally {
        //这里的代码一定会执行,可以进行相应的操作
    }
}

@end

再次运行程序,发现没有崩溃,控制台打印出了异常信息

image.png

我们可以把拿到的异常信息保存文件到沙盒或者上报到服务器,方便问题排查统计。

总结

使用NSException可以方便我们去收集app的crash信息,并对一些常见的crash问题提前做出处理,使app能够平稳运行。不足的是NSException只能针对OC类异常进行捕获,如果是Signal类异常就无能为力了,所以还要专门做Signal类处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值