我应该将[pool drain]放在@finally子句中吗?

时间:2010-12-11 17:10:14

标签: objective-c cocoa

经过多年的Java开发,我开始在Objective-C中编程。我正在努力解决的一个问题是内存管理。特别是,书籍和在线中的大多数示例似乎都没有考虑到由于例外而导致的内存泄漏。例如,请考虑以下方法:

-(void) doSomething  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

    // Allocate some autoreleased objects here

    NSString *data = [NSString stringWithString@"Hello"];

    // Do some work, exception could be thrown

    [PotentialExeptionThrower maybeThrowException];

    // Clean up autorelease objects

    [pool drain];
}

上述内容是否应该重写如下以防止任何潜在的内存泄漏?

-(void) doSomething  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

     @try {

        // Allocate some autoreleased objects here

        NSString *data = [NSString stringWithString@"Hello"];

        // Do some work, exception could be thrown

        [PotentialExeptionThrower maybeThrowException];

    } @finally {
        // Clean up autorelease objects

        [pool drain];
    }
}

由于@ try- @ catch?

,上面的代码是否效率低下

谢谢!

5 个答案:

答案 0 :(得分:4)

总的来说:不,你不应该。在异常路径上根本不应该排空池。相反,它的父池会自动耗尽。 (如果调用层次结构中的代码尝试检查异常,那么按照您的方式执行将导致崩溃,因为您的finally子句将释放它。)

例外情况是当你负责最外层池时,最有可能发生在多线程代码中。在这种情况下,如果您希望代码生成异常,则必须捕获异常并将其压缩或处理,然后排空自动释放池。 (不执行此操作将导致崩溃。如果您不自行引发任何异常,这实际上可以被认为是可接受的,因为系统框架引发的任何异常都表示编程错误并使您的程序处于未定义状态。)

答案 1 :(得分:2)

this Apple document中对此进行了解释。你不必那样做。关键是如果下游水池排水,不排水的上水池也会自动排水。所以是的,自动释放的对象的释放将被异常延迟,但它们最终会被释放。

可以这样说明:

NSAutoreleasePool* A = [[NSAutoreleasePool alloc] init];
NSAutoreleasePool* B = [[NSAutoreleasePool alloc] init];

    .... do many things. Put things in B ...

NSAutoreleasePool* C = [[NSAutoreleasePool alloc] init];

    .... do many things. Put things in C ...

[A drain]; // it automatically drains B and C, too!

请注意,您不必经常设置池。在每种方法中进行设置肯定是一种矫枉过正。通常你不会开始添加本地池,除非仪器的真实测量结果表明方法中有很多自动释放的对象。

答案 2 :(得分:2)

请注意,Mac OS X和iOS应用程序中的异常通常只保留为表示不可恢复的程序员错误。

如果您通过框架抛出异常,行为未定义

例外用于流量控制。

(正如其他人所说 - 在异常情况下不要释放池。父池将清理它。)

答案 3 :(得分:1)

不,你不应该。我知道您的经验受到多年Java的污染,您需要改变处理异常的方式。

正如名称所暗示的那样,异常不是Cocoa应用程序中正常程序流程的一部分。例外用于捕获开发人员所犯的错误,并且应该在您的应用发布之前处理。用单元测试覆盖你的数据模型,抽出每一个数据模型。

例如NSInvalidArgumentException不是你应该潜入生产代码的东西。通过单元测试验证用户输入并覆盖逻辑的边缘情况!

对于不是您的错误,并且您可以从中恢复的错误应该使用NSError个实例。它们具有适合最终用户的本地化描述的良好属性。 NSError还具有处理合适恢复选项的功能,例如“取消”“重试”

我在这里写了一篇关于iOS上的例外和错误的博文:http://blog.jayway.com/2010/10/13/exceptions-and-errors-on-ios/

答案 4 :(得分:0)

自动释放池是特殊的 - 正常的“如果你新的/ alloc / copy,你必须发布”并不完全适用。创建自动释放池时,它会放在特殊堆栈上。如果您忽略了排水池,如果排水池中的任何水池被排空,它将被排空。不需要排放一个捕获区块,但是例外可能会延迟池排水。有关详细信息,请阅读“Scope of Autorelease Pools and Implications of Nested Autorelease Pools”。