1. 程式人生 > >學會用 try,catch語法捕獲異常

學會用 try,catch語法捕獲異常

對於應用閃退,相信大家見到最多的就是“異常丟擲”這個狀況,也就是

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中抓到這個異常。