NSException这个幺蛾子搞的鬼。那么今天就来面对它。也就是利用@try 语法来捕获它。并且做出相应的善后工作。不让程序闪退。
模拟一个异常 : array 是不可变数组,然后我们在函数dosomething 中给他addobject
-(void)dosomething:(NSMutableArray*)input { [input addObject:@"test"]; }
<pre name="code" class="objc"> NSArray* array = [NSArray new]; [self dosomething:array];
然后我们运行,结果可想而知,程序闪退,并且输出如下信息:
2014-10-29 16:51:35.567 warning[3901:133943] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x786385f0 2014-10-29 16:51:35.571 warning[3901:133943] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x786385f0' *** First throw call stack: ( 0 CoreFoundation 0x008b0df6 __exceptionPreprocess + 182 1 libobjc.A.dylib 0x0053aa97 objc_exception_throw + 44 2 CoreFoundation 0x008b8a75 -[NSObject(NSObject) doesNotRecognizeSelector:] + 277 3 CoreFoundation 0x008019c7 ___forwarding___ + 1047 4 CoreFoundation 0x0080158e _CF_forwarding_prep_0 + 14 5 warning 0x0005c857 -[AppDelegate dosomething:] + 103 6 warning 0x0005c791 -[AppDelegate application:didFinishLaunchingWithOptions:] + 161 7 UIKit 0x00c5bedc -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 291 8 UIKit 0x00c5cbe7 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2869 9 UIKit 0x00c6016d -[UIApplication _runWithMainScene:transitionContext:completion:] + 1639 10 UIKit 0x00c78d30 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke + 59 11 UIKit 0x00c5ed7f -[UIApplication workspaceDidEndTransaction:] + 155 12 FrontBoardServices 0x031d79de __37-[FBSWorkspace clientEndTransaction:]_block_invoke_2 + 71 13 FrontBoardServices 0x031d746f __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 54 14 FrontBoardServices 0x031e9425 __31-[FBSSerialQueue performAsync:]_block_invoke + 26 15 CoreFoundation 0x007d47a0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 16 16 CoreFoundation 0x007ca0b3 __CFRunLoopDoBlocks + 195 17 CoreFoundation 0x007c9f0b __CFRunLoopRun + 2715 18 CoreFoundation 0x007c91ab CFRunLoopRunSpecific + 443 19 CoreFoundation 0x007c8fdb CFRunLoopRunInMode + 123 20 UIKit 0x00c5e744 -[UIApplication _run] + 571 21 UIKit 0x00c61e16 UIApplicationMain + 1526 22 warning 0x0005ccfd main + 141 23 libdyld.dylib 0x02bfeac9 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException异常原因可以看到,程序也如愿闪退。
我们对上面的代码做一些修改。
NSArray* array = [NSArray new]; @try { [self dosomething:array]; } @catch (NSException *exception) { NSLog(@"-----%@",exception.description); } @finally { NSLog(@"over"); }重新跑一遍。输出log如下
2014-10-29 16:55:31.308 warning[3942:136578] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7be13470 2014-10-29 16:55:31.309 warning[3942:136578] ------[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7be13470 2014-10-29 16:55:31.309 warning[3942:136578] over应用程序也没有闪退。
我来解释一下这段代码以及log输出。
使用try 语法调用那些可能导致异常的代码段。这里就一个函数调用。
如果有异常抛出,异常被catch捕获,并且你可以知道异常信息。也就是exception。
最后finally无论有没有异常都会走。
log 第一行是应用自身抛出的异常log,可见在应用抛出异常之后,马上被我们的catch 捕获到,并且按照我们的要求输出了异常信息。
最后进入finally里面。
当然这个语法是可以嵌套。确保异常一定会得到处理。
可以在函数 dosomething 里面加上try 语法
-(void)dosomething:(NSMutableArray*)input { @try { [input addObject:@"test"]; } @catch (NSException *exception) { NSLog(@"======= %@",exception.description);//如果这里不能处理异常,需要向外层继续抛出 @throw; } @finally { NSLog(@"finally"); } }这样在函数内部,也会有一个捕获异常的过程。值得一说的是,如果你在函数内部不能处理,需要抛出去让外层处理。
这样外层依然能在@catch中抓到这个异常。