我有一个函数,它接受一些位图数据并从中返回一个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回调来清理像素缓冲区,但还有什么?
谢谢!
答案 0 :(得分:21)
这里的拇指规则是“-release
*如果您不需要它”。
由于您之后不再需要provider
和imageRef
,您应该-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选择器。