美文网首页编写高质量代码的52个有效方法
52个有效方法(32) - 编写“异常安全代码”时留意内存管理问

52个有效方法(32) - 编写“异常安全代码”时留意内存管理问

作者: SkyMing一C | 来源:发表于2018-09-07 10:28 被阅读15次
异常安全代码
@try {

    // 可能会出现崩溃的代码

}

@catch (NSException *exception) {

    // 捕获到的异常exception

}

@finally {

    // 结果处理
    //无论是否抛出异常,其中的代码都保证会运行,且只运行一次。

}
  • 处理异常代码块,在这里如果try里出现异常,他会执行finally块里的代码。

  • 在这个过程里

    • MRC:
      手动在finally里执行release,释放对象

    • ARC:
      不会自动添加,需要开启编译器标志(-fobjc-arc-exceptions)(开启会导致占用大内存,影响运行时性能)

例子
@try {

    // 1

    [self tryTwo];

}

@catch (NSException *exception) {

    // 2

    NSLog(@"%s\n%@", __FUNCTION__, exception);

//        @throw exception; // 这里不能再抛异常

}

@finally {

    // 3

    NSLog(@"我一定会执行");

}

// 4

// 这里一定会执行

NSLog(@"try");
//tryTwo方法代码
- (void)tryTwo

{

    @try {

        // 5

        NSString *str = @"abc";

        [str substringFromIndex:111]; // 程序到这里会崩

    }

    @catch (NSException *exception) {

        // 6

//        @throw exception; // 抛出异常,即由上一级处理

        // 7

        NSLog(@"%s\n%@", __FUNCTION__, exception);

    }

    @finally {

        // 8

        NSLog(@"tryTwo - 我一定会执行");

    }

    // 9

    // 如果抛出异常,那么这段代码则不会执行

    NSLog(@"如果这里抛出异常,那么这段代码则不会执行");

}
  • 如果6抛出异常,那么执行顺序为:1->5->6->8->3->4

  • 如果6没抛出异常,那么执行顺序为:1->5->7->8->9->3->4

  • 把捕获到的异常发送至开发者的邮箱
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Override point for customization after application launch.

    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);

    return YES;

}

 

void UncaughtExceptionHandler(NSException *exception) {

    /**

     *  获取异常崩溃信息

     */

    NSArray *callStack = [exception callStackSymbols];

    NSString *reason = [exception reason];

    NSString *name = [exception name];

    NSString *content = [NSString stringWithFormat:@"========异常错误报告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[callStack componentsJoinedByString:@"\n"]];

 

    /**

     *  把异常崩溃信息发送至开发者邮件

     */

    NSMutableString *mailUrl = [NSMutableString string];

    [mailUrl appendString:@"mailto:test@qq.com"];

    [mailUrl appendString:@"?subject=程序异常崩溃,请配合发送异常报告,谢谢合作!"];

    [mailUrl appendFormat:@"&body=%@", content];

    // 打开地址

    NSString *mailPath = [mailUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:mailPath]];

}
为什么iOS很少使用try catch
  • Apple虽然同时提供了错误处理(NSError)和异常处理(exception)两种机制,但是Apple更加提倡开发者使用NSError来处理程序运行中可恢复的错误。而异常被推荐用来处理不可恢复的错误。

  • try catch无法捕获UncaughtException,而oc中大部分crash如:内存溢出、野指针等都是无法捕获的,而能捕获的只是像数组越界之类(这真心需要catch么?),所以try catch对于oc来说,比较鸡肋。

要点
  1. 捕获异常时,一定要注意将try块内所创立的对象清理干净。

  2. 在默认情况下,ARC不生成安全处理一次所需的清理代码。开启编译器标志后(-fobjc-arc-exceptions),可生成这种代码,不过会导致应用程序变大,而且会降低运行效率。

相关文章

网友评论

    本文标题:52个有效方法(32) - 编写“异常安全代码”时留意内存管理问

    本文链接:https://www.haomeiwen.com/subject/fpdxgftx.html