使用UIImagePNGRepresentation保存图像时出现内存问题

时间:2011-03-07 00:27:07

标签: iphone objective-c memory-management memory-leaks uiimage

我的应用程序在动画中使用了大量缩放图像。为了避免跳帧,我在运行动画之前缩放图像并保存它们。这是我保存图像的代码:

+ (void)saveImage:(UIImage *)image withName:(NSString *)name {
    NSData *data = UIImagePNGRepresentation(image);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *directory = [paths objectAtIndex:0];
    NSString *fullPath = [directory stringByAppendingPathComponent:name];
    [fileManager createFileAtPath:fullPath contents:data attributes:nil];

}

不幸的是,当我反复调用此函数时,我遇到了内存问题。我想我正在努力节省大约10MB的图像。我想也许问题在于自动释放的变量 - 也许我应该分配数据,并在最后发布。但我找不到UIImagePNGRepresentation的分配版本。有人可以帮忙吗?

2 个答案:

答案 0 :(得分:4)

UIImagePNGRepresentation返回一个自动释放的NSData对象。换句话说,一旦到达最近的封闭NSAutoreleasePool块的释放(或排出)调用,分配的数据将被释放。

如果从循环中调用上面的代码,那么您的代码可能永远不会有机会自动释放所有内存。在这种情况下,您可以将调用封装在您自己的NSAutoreleasePool中:

for (int i = 0; i < 10; i++) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [self saveImage:someImage withName:@"someName.png"]; 

    [pool drain];
}

N.B。我相信与使用JPG(UIImageJPGRepresentation)相比,使用PNG这种方式相当慢。仅供参考。

答案 1 :(得分:1)

外环看起来像什么?如果是这样的话:

for(n = 0; n < 1000; n++)
{
    ... something ...
    [class saveImage:image withName:name];
}

然后将内容留在自动释放池中可能是您​​的问题。仅当调用堆栈完全展开回运行循环时才会释放自动释放池(因为否则您将无法使用自动释放的东西作为返回结果)。鉴于您没有发布任何内容,您可以尝试将代码修改为:

+ (void)saveImage:(UIImage *)image withName:(NSString *)name {
    // create a local autorelease pool; this one will retain objects only
    // until we drain it
    NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];

    NSData *data = UIImagePNGRepresentation(image);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *directory = [paths objectAtIndex:0];
    NSString *fullPath = [directory stringByAppendingPathComponent:name];
    [fileManager createFileAtPath:fullPath contents:data attributes:nil];

    // drain the pool, which acts like release in reference counted environments
    // but also has an effect in garbage collected environments
    [localPool drain];
}

因此,对于图像的每次保存,您都可以创建自己的自动释放池。最近初始化的自动释放池自动设置为从那时起捕获所有自动释放的对象。在像iOS这样的垃圾收集环境中,在它上面调用'drain'会导致它被释放,并且它立即释放的所有对象都会被释放。