iOS 发生在Objective-C层(OC Exception)的异常

发生在Objective-C层的奔溃异常,称为:OC Exception

1. NSException介绍

如果说你对NSException这个类不了解,那这下面这张图的输出内容在开发过程中肯定经常和你见面:

iOS 发生在Objective-C层(OC Exception)的异常_第1张图片
图片.png

附导致上图中抛出错误的代码:

NSMutableArray *array = [NSMutableArray array];
NSString *strObj = nil;
[array addObject:strObj];

这样的错误是致命的,也就说在不做任何容错的情况下,程序直接Crash,也就是俗称”闪退“,解决这类iOS提供的SDK导致的崩溃异常可以使用NSSetUncaughtExceptionHandler来进行处理,附GitHub链接:

https://github.com/minibear0523/UncaughtExceptionHandler

但App奔溃的的原因还有内存访问错误、重复释放等问题,这些异常NSSetUncaughtExceptionHandler是无法处理的,因为这类错误发送的是SIGNAL。

2. NSException处理

苹果提供了NSError错误处理和NSException异常处理两种机制,NSError用来处理程序中可恢复的错误(通常情况下程序可以继续运行),而NSException用来处理不可恢复的错误(会导致程序终止的严重异常)

在没有研究NSException之前,苹果开发一直有个令我非常疑惑的地方,就是Java中经常使用的try{****} catch{****},为什么在iOS代码中几乎见不到?这个得益于ARC自动内存管理,在大多数时候开发者并不需要手动管理内存(并不是绝对安全),但是如果你面对某段有潜在奔溃风险的代码,则可以使用try catch来捕捉异常:

@try {
    //放有可能会出现异常错误的代码
}
@catch (NSException *exception) {
    //只有try块中的代码出现了异常才会执行,用于匹配处理抛出的异常
}
@finally {
    //无论是否抛出异常,都会执行的代码
}

整个执行过程会有以下几种情况:

  1. try块代码没有发生异常,则程序会执行try块内、finally块内、finally块之后的代码;
  2. try块代码发生了异常,并且有catch捕捉匹配的异常,则程序在try块内发生异常后剩下的代码将不再执行,跳转到catch块内并抛出NSException对象;
  3. try块代码发生了异常,并且有catch没有能匹配捕捉,则程序会执行try和finally块中的代码,并将异常返回给调用者,finally块之后的代码也不执行。

通过try catch方法可以解决很多问题,上面addObject插入nil对象的奔溃也可以被妥善解决:

    @try {
        [array addObject:strObj];
    }
    @catch (NSException *exception) {
        //打印exception输出:
        //exception.name = NSInvalidArgumentException
        //exception.reason = *** -[NSArrayM insertObject:atIndex:]: object cannot be nil
        //还可以通过exception.callStackSymbols查看函数堆栈,发现对应异常错误发生在哪个类中的哪一行
    }
    @finally {
        
    }

3. Foundation常见奔溃异常

Foundation是我们在开发过程中最常使用的框架,与CoreFoundation不同Foundation提供的是Objective-C接口,他主要提供了:数据类型(数组、字典、集合等)、字符串、时间、日期、URL、线程、RunLoop等。

这也造成了很多异常的发送,比如:

  • 数组越界
  • 可变数组插入空对象
  • KVO在addObserver后不remove
  • 调用对象方法找不到selector对应的函数时,消息转发

可以利用Runtime特性在Category使用新函数替换掉系统的存在异常风险的方法

4. 在发布到App Store的版本中,通过上述手段捕捉的异常如何得知?

由于我们将异常捕获了,所以程序不会产生奔溃现象,那么在这样的情况下作为开发者如何收集这些被捕获的异常呢?显然像友盟、Bugly这样的第三方SDK根本不管用了,其实完全可以自给自足,我是通过腾讯Mars框架中的Xlog来实现的,并且人家的框架生成的.xlog文件还支持非对称加密,保证了在网络传输过程中即使被截获也不用担心泄漏。
附上Mars的GitHub链接:

https://github.com/Tencent/mars

如果本文对你有所帮助,记得点击一下喜欢哈

你可能感兴趣的:(iOS 发生在Objective-C层(OC Exception)的异常)