buffer->CGImageRef->UIImage 的正确内存管理模式是什么?

发布于 2024-08-19 00:25:25 字数 725 浏览 3 评论 0原文

我有一个函数,它接受一些位图数据并从中返回一个 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 后在此函数末尾释放像素,然后使用 UIImage,则会崩溃。如果我在创建 UIImage 后释放提供程序或 imageRef,我不会看到崩溃,但它们显然一直在传递像素,所以我对释放这些中间状态感到不安。

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

谢谢!

I have a function that takes some bitmap data and returns a UIImage * from it. It looks something like so:

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];
}

Can anyone explain exactly who owns what memory here? I want to clean up properly, but I'm not sure how to do it safely. Docs are fuzzy on these. If I free pixels at the end of this function after creating the UIImage, and then use the UIImage, I crash. If I Release the provider or the imageRef after creating the UIImage, I don't see a crash, but they're apparently passing the pixels all the way through, so I'm skittish about releasing these intermediate states.

(I know per CF docs that I should need to call release on both of the latter because they come from Create functions, but can I do that before the UIImage is used?) Presumably I can use the provider's dealloc callback to cleanup the pixels buffer, but what else?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

十雾 2024-08-26 00:25:25

这里的经验法则是“-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 从一开始就已经为零。)

The thumb rule here is "-release* it if you don't need it".

Because you no longer need provider and imageRef afterwards, you should -release all of them, i.e.

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

pixel is not managed by ref-counting, so you need to tell the CG API to free them for you when necessary. Do this:

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

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

By the way, you can use +imageWithCGImage: instead of [[[* alloc] initWithCGImage:] autorelease]. Even better, there is +imageWithData: so you don't need to mess with the CG and malloc stuff.

(*: Except when the retainCount is already supposedly zero from the beginning.)

小矜持 2024-08-26 00:25:25
unsigned char * Pixels = malloc(...);

您拥有 pixels 缓冲区,因为您对它进行了 malloc。

CGDataProviderRef 提供商 = CGDataProviderCreateWithData(NULL, 像素, 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。或者,按照 KennyTM 的建议,使用 imageWithData:

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

You own the pixels buffer because you mallocked it.

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

Core Graphics follows the Core Foundation rules. You own the data provider because you Created it.

You didn't provide a release callback, so you still own the pixels buffer. If you had provided a release callback, the CGDataProvider object would take ownership of the buffer here. (Generally a good idea.)

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

You own the CGImage object because you Created it.

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

You own the UIImage object because you allocked it.

You also still own the CGImage object. If the UIImage object wants to own the CGImage object, it will either retain it or make its own copy.

return [image autorelease];

You give up your ownership of the image.

So your code leaks the pixels (you didn't transfer ownership to the data provider and you didn't release them yourself), the data provider (you didn't release it), and the CGImage (you didn't release it). A fixed version would transfer ownership of the pixels to the data provider, and would release both the data provider and the CGImage by the time the UIImage is ready. Or, just use imageWithData:, as KennyTM suggested.

太阳公公是暖光 2024-08-26 00:25:25
unsigned char * pixels = malloc(...);

使用 CGImageCreate 后,我也遇到了 malloc/free 问题
我终于找到了很好又简单的解决方案。
我只是将 line: 替换

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

为:

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

之后我就可以释放 malloced 内存:

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

I also had problem with malloc/free after using CGImageCreate
I finally found good and simple solution.
I just replace line:

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

with:

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

Just after that i could free mallocked memory:

free (pixels);
安人多梦 2024-08-26 00:25:25

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

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

Aye, this code makes me queasy. As an old rule-to-live by, I try not to mix and match C and C++, and C/Objective-C in the same function/method/selector.

How about breaking this up into two methods. Have change this makeAnImage into makeAnImageRef and pull up the UIImage creation into another Obj-C selector.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文