缓冲区> CGImageRef-> UIImage的内存管理模式是什么?

时间:2010-01-26 03:46:32

标签: iphone uiimage core-graphics quartz-2d core-foundation

我有一个函数,它接受一些位图数据并从中返回一个UIImage *。它看起来像这样:

UIImage * makeAnImage() 
{
    unsigned char * pixels = malloc(...);
    // ...
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL);
    CGImageRef imageRef = CGImageCreate(..., provider, ...);
    UIImage * image =  [[UIImage alloc] initWithCGImage:imageRef];
    return [image autorelease];
}

有谁能确切地解释谁在这里拥有什么记忆?我想要正确清理,但我不确定如何安全地进行清理。文档在这些上是模糊的。如果在创建UIImage之后我在此函数末尾有free个像素,然后使用UIImage,我就崩溃了。如果我在创建UIImage之后释放提供者或imageRef,我没有看到崩溃,但他们显然已经完全传递了像素,所以我对释放这些中间状态感到不安。

(我知道每个CF文档我都需要在后者上调用release,因为它们来自Create函数,但我可以在使用UIImage之前执行此操作吗?)大概我可以使用提供程序的dealloc回调来清理像素缓冲区,但还有什么?

谢谢!

4 个答案:

答案 0 :(得分:21)

这里的拇指规则是“-release *如果您不需要它”。

由于您之后不再需要providerimageRef,您应该-release所有这些,即

UIImage * image =  [[UIImage alloc] initWithCGImage:imageRef];
CGDataProviderRelease(provider);
CGImageRelease(imageRef);
return [image autorelease];

pixel不是通过引用计数来管理的,因此您需要告诉CG API在必要时为您释放它们。这样做:

void releasePixels(void *info, const void *data, size_t size) {
   free((void*)data);
}
....

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, releasePixels);

顺便说一下,您可以使用+imageWithCGImage:代替[[[* alloc] initWithCGImage:] autorelease]。更好的是,有+imageWithData:所以你不需要弄乱CG和malloc的东西。

(*:除非retainCount从一开始就被认为是零。)

答案 1 :(得分:8)

unsigned char * pixels = malloc(...);

您拥有pixels缓冲区,因为您已将它集中在一起。

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL);

Core Graphics遵循Core Foundation规则。您拥有数据提供者是因为Created它。

您没有提供发布回调,因此您仍然拥有pixels缓冲区。如果您提供了发布回调,则CGDataProvider对象将在此处获取缓冲区的所有权。 (通常是一个好主意。)

CGImageRef imageRef = CGImageCreate(..., provider, ...);

您拥有CGImage对象,因为您创建了它。

UIImage * image =  [[UIImage alloc] initWithCGImage:imageRef];

你拥有UIImage对象,因为你已经把它拿走了。

您还拥有CGImage对象。如果UIImage对象想要拥有CGImage对象,它将保留它或制作自己的副本。

return [image autorelease];

您放弃了对图片的所有权。

所以你的代码泄漏了像素(你没有将所有权转移到数据提供者而你自己没有发布),数据提供者(你没有发布它)和CGImage(你没有释放它)。固定版本会将像素的所有权转移到数据提供者,并在UIImage准备好时释放数据提供者和CGImage。或者,像KennyTM建议的那样使用imageWithData:

答案 2 :(得分:1)

unsigned char * pixels = malloc(...);

使用CGImageCreate后我也遇到了malloc / free的问题 我终于找到了简单易行的解决方案。 我只是替换行:

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL);

使用:

NSData *data = [NSData dataWithBytes:pixels length:pixelBufferSize];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);

之后我可以释放mallocked内存:

free (pixels);

答案 3 :(得分:-2)

是的,这段代码让我感到不安。作为一个古老的规则,我尽量不在相同的函数/方法/选择器中混合和匹配C和C ++,以及C / Objective-C。

如何将其分解为两种方法。将此makeAnImage更改为makeAnImageRef并将UIImage创建拉入另一个Obj-C选择器。