异常处理的使用的格式基本就是:
//如果@try中的代码会导致程序崩溃,就会去到@catch
} @catch(NSException *exception) {
//如果@try中的代码有问题(导致崩溃),就会来到@catch
//在这里可以进行相应的处理操作
//如果你要抛出异常(让程序崩溃),就写上 @throw exception
} @finally {
//@finally中的代码是一定会执行的
}
觉得需要掌握以下几个方面的内容:
1 要会创建NSException对象,并且会使用@throw抛出异常
2 了解异常处理的作用
使用@try进行异常处理,一开始会有类似下面两个问题弄不明白:
1 既然异常发生了,程序一定会退出,那还需要@final逻辑干嘛,程序退出了一切都重新开始不就行了
2 异常发生后,然后判断是属于哪种异常,使用@catch分别处理的意图是什么呢
举个简单的例子,对数组越界访问:
- (void)testCode {
NSArray *arr = @[@"abc"];
NSString *name = [arr objectAtIndex:1];
NSLog(@">---%@", name);
if(!name) {
NSLog(@">---取值失败");
} else {
NSLog(@">---取值成功");
}
}
控制台打印的信息:
2023-02-0317:35:12.956564+0800OCTestLine[22690:1921426] *** Terminating app due to uncaught exception'NSRangeException', reason:'*** __boundsFail: index 3 beyond bounds [0 .. 1]'*** Firstthrow call stack:
(
0CoreFoundation0x00007fff2dd5ff53__exceptionPreprocess +2501libobjc.A.dylib0x00007fff63e25835objc_exception_throw +482CoreFoundation0x00007fff2de22d3a_CFThrowFormattedException +2023CoreFoundation0x00007fff2de2a203-[__NSArrayI getObjects:range:].cold.1+04CoreFoundation0x00007fff2dcbd061-[__NSSingleObjectSetI member:] +05TestDemo0x0000000100000d97-[TestClass testCode] +1356 +447TestDemo0x0000000100000c47main +878libdyld.dylib0x00007fff651882e5start +1)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
关于这种越界取值的情况,程序会直接抛出异常,抛出异常的结果就是程序crash(崩溃),这在程序开发过程中相对于“错误”,“异常”导致crash更容易定位bug,这样直截了当地crash的确也没什么,定位bug、修改代码、重新运行就行了,因此在软件开发过程中,“异常处理”的确没什么用。但是如果有以下需求呢?
1 程序闪退之前,我想把这个“异常”信息记录下来,或者记录在本地,或者上传记录在服务器上,方便后期修复优化代码;
2 程序闪退之前,我想把一些“操作”做完,以确保整个系统的安全性;
这样的需求并不过分,比如用户下载了已经发布的版本,使用过程中出现了闪退,肯定是需要进行crash统计的,方便程序员定位问题,腾讯Bugly就是基于此需求开发的框架。
另外,使用异常处理有个现实情况是,当App出现异常闪退了,但是并没有真正的“杀死”进程,这个时候是可以继续使用该App的进程继续做其他操作的(比如上传异常信息到服务器)。
- (void)testCode {
NSString *name;
@try {
NSArray *arr = @[@"abc"];
name = [arr objectAtIndex:1];
NSLog(@">---%@", name);
} @catch(NSException *exception) {
NSLog(@">---%@", exception);
for(inti =1; i <10; i++) {
sleep(1);
NSLog(@">---将错误信息上传服务器进度:%d%%", i*10);
}
} @finally {
for(inti =10; i >0; i--) {
sleep(1);
NSLog(@">---退出程序倒计时:%d", i);
}
if(!name) {
NSLog(@">---通知服务器取值失败");
} else {
NSLog(@">---通知服务器取值成功");
}
}
}
在控制台的打印结果如下:
2023-02-03 17:28:50.937048+0800 TestDemo[113258:333899] >---*** __boundsFail: index3beyond bounds [0..1]
2023-02-03 17:28:51.938338+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:10%
2023-02-03 17:28:52.939736+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:20%
2023-02-03 17:28:53.941213+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:30%
2023-02-03 17:28:54.937048+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:40%
2023-02-03 17:28:55.937048+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:50%
2023-02-03 17:28:56.937048+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:60%
2023-02-03 17:28:57.937048+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:70%
2023-02-03 17:28:58.937048+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:80%
2023-02-03 17:28:59.937048+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:90%
2023-02-03 17:29:00.937048+0800 TestDemo[113258:333899] >---将错误信息上传服务器进度:100%
2023-02-03 17:29:01.937048+0800 TestDemo[113258:333899] >---退出程序倒计时:10
2023-02-03 17:29:02.937048+0800 TestDemo[113258:333899] >---退出程序倒计时:9
2023-02-03 17:29:03.958486+0800 TestDemo[113258:333899] >---退出程序倒计时:8
2023-02-03 17:29:04.958486+0800 TestDemo[113258:333899] >---退出程序倒计时:7
2023-02-03 17:29:05.963303+0800 TestDemo[113258:333899] >---退出程序倒计时:6
2023-02-03 17:29:06.963303+0800 TestDemo[113258:333899] >---退出程序倒计时:5
2023-02-03 17:29:07.965136+0800 TestDemo[113258:333899] >---退出程序倒计时:4
2023-02-03 17:29:08.967182+0800 TestDemo[113258:333899] >---退出程序倒计时:3
2023-02-03 17:29:09.969092+0800 TestDemo[113258:333899] >---退出程序倒计时:2
2023-02-03 17:29:10.970962+0800 TestDemo[113258:333899] >---退出程序倒计时:1
2023-02-03 17:29:10.971614+0800 TestDemo[113258:333899] >---通知服务器取值失败
Program ended with exit code: 0
关于控制台打印的信息,有两点说明:
1 仔细看打印的时间,可以知道,异常发生后,app闪退后,后台进程并没有退出,在用户通过“多任务”进行删除app之前,依然可以运行代码做很多事;
2 使用@try正常处理异常,程序是属于正常退出的,“Program ended with exit code:0”