iOS的try catch是与非

OC中得异常处理符号和C++、JAVA相似。再加上使用NSException,NSError或者自定义的类,你可以在你的应用程序里添加强大的错误处理机制。

异常处理机制是由这个四个关键字支持的:@try,@catch,@thorw,@finally。当代码有可能出现异常时,我们把他放到@try语句块中。@catch()块包含了处理@try块里的抛出的异常的逻辑。无论异常是否发生,@finally块里面的语句都会执行。如果直接使用@throw块来抛出异常,这个异常本质上是一个OC的对象,可以使用NSException对象,但是不局限于他们。

下面再来几个异常示例热热身:

1、让我们人为的制造一个异常,就像这样:

NSArray *array = @[];

NSString *firstObject = [array objectAtIndex:1];

很明显,数组越界,运行后必然崩溃。崩溃信息如下:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds for empty array'

*** First throw call stack:

(

0 CoreFoundation 0x000000010dfbec65 __exceptionPreprocess + 165

1 libobjc.A.dylib 0x000000010dc57bb7 objc_exception_throw + 45

2 CoreFoundation 0x000000010deb517e -[__NSArrayI objectAtIndex:] + 190

……

}

2、让我们加上异常处理后,就像这样:

NSArray *array = @[];

@try {

    NSString *firstObject = [array objectAtIndex:1];

}

@catch (NSException *exception) {

    NSLog(@"exception name is %@,reason is %@",exception.name,exception.reason);

}

@finally {

    NSLog(@"@finally里的代码始终会执行的");

}

运行,这时候程序并没有崩溃,再看日志信息:

exception name is NSRangeException,reason is *** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds for empty array

@finally里的代码始终会执行的。

看来我们已经成功捕获到了这个异常,而且这个异常名字叫做NSRangeException。

这时候你可能会好奇除了NSRangeException异常,还有什么类型的异常?

通过查看NSRangeException的头文件发现,其中还有这些异常:

/***************Generic Exception names***************/

FOUNDATION_EXPORT NSString * const NSGenericException;

FOUNDATION_EXPORT NSString * const NSRangeException;

FOUNDATION_EXPORT NSString * const NSInvalidArgumentException;

FOUNDATION_EXPORT NSString * const NSInternalInconsistencyException;

FOUNDATION_EXPORT NSString * const NSMallocException;

FOUNDATION_EXPORT NSString * const NSObjectInaccessibleException;

FOUNDATION_EXPORT NSString * const NSObjectNotAvailableException;

FOUNDATION_EXPORT NSString * const NSDestinationInvalidException;

FOUNDATION_EXPORT NSString * const NSPortTimeoutException;

FOUNDATION_EXPORT NSString * const NSInvalidSendPortException;

FOUNDATION_EXPORT NSString * const NSInvalidReceivePortException;

FOUNDATION_EXPORT NSString * const NSPortSendException;

FOUNDATION_EXPORT NSString * const NSPortReceiveException;

FOUNDATION_EXPORT NSString * const NSOldStyleException;

所有常量名字都定义为常量。既然有这么多异常,那我们如何根据不同的异常信息给予不同的提示呢?那就catch中根据异常名字进行判断处理呗。

if ([exception.name isEqualToString:NSRangeException]) {
    //do...
}

3、抛出异常

抛出异常就是向上层抛,谁调用谁处理。如果上层未处理则会引发崩溃。

- (void)viewDidLoad {

    [super viewDidLoad];

    @try {

        [self testException];

    }

    @catch (NSException *exception) {

        NSLog(@"exception name is %@,reason is %@",exception.name,exception.reason);

    }

    @finally {

        NSLog(@"@finally里的代码始终会执行的");

    }

}

- (void)testException

{

    NSException *excetpion = [NSException exceptionWithName:@"MyException" reason:@"test exception" userInfo:nil];

    @throw excetpion;

    //或者这样

    //[NSException raise:@"MyException" format:@"test exception"];

}

4、如何使用自定义异常?

(1)新建一个类,并继承NSException

@interface MyException : NSException

@end

(2)导入自定义异常,然后抛出MyException

(3)捕获自定义异常,并进行处理。

就像这样写:

- (void)viewDidLoad {

    [super viewDidLoad];

    @try {

        [self testException];

    }

    @catch (MyException *exception) {

        NSLog(@"exception name is %@,reason is %@",exception.name,exception.reason);

    }

    @finally {

        NSLog(@"@finally里的代码始终会执行的");

    }

}

- (void)testException

{

    NSException *excetpion = [MyException exceptionWithName:@"MyException" reason:@"test exception" userInfo:nil];

    @throw excetpion;

    // [MyException raise:@"MyException" format:@"test exception"];

}

 

5、捕获崩溃异常

虽然有了try catch异常捕获,但是还是存在崩溃异常无法捕获到的。我可以通过下面的方式来获取崩溃日志:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Override point for customization after application launch.

    //设置异常处理Handler

    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);

    return YES;

}

void UncaughtExceptionHandler(NSException *exception) {

    //下面代码可以获取到崩溃异常的相关信息

     NSArray *callStack = [exception callStackSymbols];

     NSString *reason = [exception reason];

     NSString *name = [exception name];

     //将收集到的崩溃日志进行处理,上报服务器或者提示用户邮件发送等等。。。

}

 


最后让我们来说下iOS开发中到底需要不需要使用try catch来捕获异常呢?

通过度娘来看,都是不推荐在代码中使用try catch的,既然苹果给我们提供了try catch,为什么大家都不推荐用呢?原因如下:

1、因为try catch无法捕获UncaughtException,而OC中大部分crash如:内存溢出、野指针等都是无法捕获的,而能捕获的只是像数组越界之类(这真心需要catch么?注:完全可以通过代码判断避免),所以try catch对于OC来说,比较鸡肋。

2、简单的来说,Apple虽然同时提供了错误处理(NSError)和异常处理(exception)两种机制,但是Apple更加提倡开发者使用NSError来处理程序运行中可恢复的错误。而异常被推荐用来处理不可恢复的错误。 原因有几个,在非gc情况下,exception容易造成内存管理问题(文档有描述即使是arc下,也不是安全的);exception使用block造成额外的开销,效率较低等等,另外这也的确是Cocoa开发者的习惯。

3、很多人在编程中,错误了使用了Try-Catch,把异常处理机制用在了核心逻辑中。把其当成了一个变种的GOTO使用。把大量的逻辑写在了Catch中。弱弱的说一句,这种情况干嘛不用ifelse呢。

综上3点原因,建议大家还是在代码中少用,可以通过判断是否非空、判断数组是否越界等方法进行处理。但是如果需要在代码中处理一些异常,也是可以的。

 

尊重原创内容,转载请注明出处
本文链接地址: https://www.awnlab.com/archives/115

为您推荐

发表评论

邮箱地址不会被公开。 必填项已用*标注