14

我有一个函数,它接受一些位图数据并从中返回一个 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];
}

谁能在这里准确解释谁拥有什么记忆?我想正确清理,但我不确定如何安全地清理。文档对这些内容很模糊。如果我free在创建 UIImage 后在此函数的末尾像素,然后使用 UIImage,我会崩溃。如果我在创建 UIImage 后释放提供程序或 imageRef,我看不到崩溃,但它们显然一直在传递像素,所以我对释放这些中间状态感到不安。

(我知道根据 CF 文档,我应该在后者上调用 release,因为它们来自 Create 函数,但我可以在使用 UIImage 之前这样做吗?)大概我可以使用提供者的 dealloc 回调来清理像素缓冲区,但还有什么?

谢谢!

4

4 回答 4

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从一开始就应该是零。)

于 2010-01-26T05:42:33.423 回答
8
unsigned char * pixels = malloc(...);

您拥有pixels缓冲区,因为您将其锁定。

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

Core Graphics 遵循 Core Foundation 规则。您拥有数据提供者,因为您创建了它。

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

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

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

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

您拥有 UIImage 对象,因为您分配了它。

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

return [image autorelease];

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

所以你的代码泄露了像素(你没有将所有权转移给数据提供者,你也没有自己发布它们)、数据提供者(你没有发布它)和 CGI​​mage(你没有发布它) . 固定版本会将像素的所有权转移给数据提供者,并在 UIImage 准备好时释放数据提供者和 CGI​​mage。或者,就像imageWithData:KennyTM 建议的那样使用 。

于 2010-01-26T21:58:23.187 回答
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);
于 2012-02-01T22:19:36.887 回答
-2

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

把它分成两种方法怎么样。将此 makeAnImage 更改为 makeAnImageRef 并将 UIImage 创建拉到另一个 Obj-C 选择器中。

于 2010-01-26T05:25:29.223 回答