iOS开发ARC、MRC不捕获异常的原因

2020-11-10  本文已影响0人  晨阳Xia

MRC手动管理引用计数时

   @try {
            EOCSomeClass *object = [[EOCSomeClass alloc] init];
            [object doSomethingThatMayThrow];
            [object release]
   }
  @catch(...){
           NSLog(@"Whoops, there was an error. Oh well...")
  }
乍一看上去似乎没有问题,但如果doSomethingThatMayThrow抛出异常了呢?由于异常会令执行过程终止并跳出catch块,因而其后的那行release代码不会运行。在这种情况下,如果代码抛出异常,那么对象就泄漏了。这么做不好。解决办法使用@finally块,无论是否抛出异常,其中的代码都会保证运行,且只运行一次。代码可更改为:
    @try {
             EOCSomeClass *object = [[EOCSomeClass alloc] init];
             [object doSomethingThatMayThrow];
    }
   @catch(...){
            NSLog(@"Whoops, there was an error. Oh well...")
   }
   @finally {
           [object release]
   }
注意,由于@finally块也引用object对象,所以必须把它从@try块里移到外面去。如果@try逻辑非常复杂,含有多条语句,那么很容易就会因为忘记某个对象而导致内存泄漏

在ARC环境下

    @try {
             EOCSomeClass *object = [[EOCSomeClass alloc] init];
             [object doSomethingThatMayThrow];
    }
   @catch(...){
            NSLog(@"Whoops, there was an error. Oh well...")
   }
由于ARC中不能调用release,所以无法像MRC手动管理引用计数那样把释放操作移到@finally块中。你可能认为这种情况ARC自然会处理。但实际上不会自动处理,因为这样做需要加入大量样板代码,以便跟踪待清理的对象,从而抛出异常是将起释放。可是,这段代码会严重影响运行期的性能,即便在不抛出异常时也是如此。而且添加进来的额外代码还会明显增加应用程序的大小。这些副作用都不甚理想。
虽然默认状况下未开启,但ARC依然能生成这种安全处理异常所用的附加代码。-fobjc-arc-exception 这个编译标志用来开启此功能。其默认不开启的原因是:在Objective-C代码中,只有应用程序必须因异常状况而中止是才应抛出异常。因此,如果应用程序即将终止,那么是否还会发生内存泄漏就已经无关紧要了。在应用程序必须立即终止的情况下,还去添加安全处理异常所用的附加代码是没有意义的。
上一篇 下一篇

猜你喜欢

热点阅读