类方法中是否有自动释放池?

时间:2010-05-08 17:28:56

标签: iphone memory-management

我有一个生成UIImage的类方法,如下所示:

+ (UIImage*)imageWithFileName:(NSString*)imgFile {
    UIImage *img = nil;

    NSBundle *appBundle = [NSBundle mainBundle];
    NSString *resourcePath = [appBundle pathForResource:imgFile ofType:nil];

    if (resourcePath != nil) {
        NSURL *imageURL = [NSURL fileURLWithPath:resourcePath];
        NSData *data = [[NSData alloc] initWithContentsOfURL:imageURL];

        img = [UIImage imageWithData:data]; // should be autoreleased!!

        [data release];
    }

    return img;
}

然而,当我使用它时,图像数据永远不会被释放。这肯定有一个内存错误,虽然我没有违反我所知道的任何内存管理规则。我的猜测是,因为这是一个从实例方法调用的类方法,所以没有活动的自动释放池,或者只是在我退出应用程序时才会耗尽。那可能是对的吗?

4 个答案:

答案 0 :(得分:3)

将数据传递到img后,它就会失控。 UIImage可能会在其内部实现中保留原始数据。但没关系。从您的角度来看,您已适当地发布了data,并且完全取决于img来确定是否希望将其保留。

您是否明确保留了返回的UIImage?或者将它传递给另一个班级?例如,如果您将其放入UIView,视图将保留img,直到不再需要它为止。

关于你的明确问题:有一个主要的运行循环AutoreleasePool。它通常会在每个事件循环后耗尽。

答案 1 :(得分:2)

UIImage会保留图像数据,因此如果您实际上是在泄漏内存,则应检查是否释放了返回的图像。

数据变量保留计数为:

  • 分配:1
  • 使用数据创建图像:2
  • [数据发布]:1

所以直到img没有被释放,提供的数据才被释放(这是有意义的,因为图像需要数据)

您可以使用retaincount来检查NSObject派生项目的当前保留计数

答案 2 :(得分:1)

我认为真正的问题是,你如何衡量内存未被释放。

自动释放池都与您所在的线程和runloop相关 - 因为它们在调用一直返回主runloop时释放内存。无论你是在调用类方法还是实例方法甚至是C函数,自动释放在所有情况下都会起作用。

我知道在您的测试中您发现存在差异,但是如果您看到其他原因之间存在差异,那么简单地说 - 因为如果您在同一个runloop中,自动释放在整个系统中的工作方式与释放内存的效果相同

答案 3 :(得分:0)

经过一些测试后我发现,问题确实与Autorelease Pools有关。如果我在实例方法中使用完全相同的代码,那绝对没有问题。

但是只要我在类方法中使用它,自动释放的UIImage对象永远不会被释放。无论自动释放池堆栈的自动释放池是类方法中最顶层的,它与实例方法严重不同。我很确定现在类方法会收到一个非常低级别的自动释放池,只有在应用程序退出时才会耗尽或释放。

所以要小心在类方法中做自动释放的东西。当然,在本地创建ARP并没有任何帮助,因为您可能需要(就像我在这种情况下所做的那样)是返回一个自动释放的对象。

我将我的代码更改为+ newImageWithFileName:并返回一个非自动释放的对象,因此接收器必须释放它或者可以发送-autorelease。

我希望有人可以提供有关此问题的更多详细信息。