imageWithCGImage和内存问题

17
如果我使用 [UIImage imageWithCGImage:],并传递一个 CGImageRef,那么我是否需要释放 CGImageRef?还是当 UIImage 被释放时会自动处理它?
该文档并非完全清楚。它说:“此方法不缓存图像对象。”
最初,我在将其传递给 imageWithCGImage: 后调用了 CGImageRelease 来释放 CGImageRef,但这导致模拟器中出现了 malloc_error_break 警告,称正在发生双重释放。

2
我建议在https://bugreport.apple.com/上提交文档错误报告,要求他们澄清这个问题。 - Peter Hosey
8个回答

8
根据Cocoa内存管理基本规则,当拥有对象不再需要时,应释放所拥有的对象。其他对象应自行负责获取和释放所有权。如果UIImage需要一个对象持续存在但没有保留或复制它,则这是UIImage实现中的错误,应将其报告为错误。

4

我在Snow Leopard上的XCode 3.2.1也遇到了与Jason差不多的问题。

我查看了使用imageWithCGImage的iPhone示例代码,他们总是在调用imageWithCGImage之后使用CGImageRelease释放CGImageRef

那么,这是模拟器中的一个错误吗?每次我使用CGImageRelease时,控制台都会出现malloc_error_break警告。


这应该是对Jason答案的评论,或者是一个新问题,因为SO不是一个论坛。 - outis
我不能评论他人的帖子,因为我的“声望”不够。此外,这不是一个新问题。我只是建议可能只会在模拟器上发生问题,而不是在设备上。 - Lextar

2

UIImage 中关于 CGImage 的所有权不明确。文档似乎并没有保证不会复制 CGImage,因此我们必须自己处理这个问题。

我使用了一个新的 UIImage 子类来解决这个问题。只需保留传递的 CGImage,并在 dealloc 时释放它。

以下是示例。

@interface  EonilImage : UIImage
{
    @private
    CGImageRef      sourceImage;
}
- (id)initWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation;

@end



@implementation     EonilImage

- (id)initWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation
{
    self    =   [super initWithCGImage:imageRef scale:scale orientation:orientation];

    if (self) 
    {
        sourceImage =   imageRef;
        CGImageRetain(imageRef);
    }

    return  self;
}
- (void)dealloc
{
    CGImageRelease(sourceImage);
    [super dealloc];
}
@end

因为 -[UIImage CGImage] 属性返回的 CGImage 不保证与传递给初始化方法的 CGImage 相同,所以该类会单独存储 CGImage

0

不确定这是否有帮助,但我曾经遇到过类似的问题。 我阅读了答案,然后按照以下步骤进行操作,似乎已经解决了:

CGImageRef cgImage = [asset thumbnail];
    UIImage *thumbImage = [[UIImage imageWithCGImage:cgImage ]retain];
    UIImageView *thumbImageView = [[UIImageView alloc] initWithImage:thumbImage];
    CGImageRelease(cgImage);

我按照建议使用了autorelease,但还不够。 当我将图像添加到UIImageView后,我释放了cgImage。
它没有崩溃,并且很好地被释放了。为什么——我不知道,但它起作用了。

顺便说一下,资产缩略图部分是来自ALAsset库,你可能需要其他东西。


似乎你正在这里泄露thumbImage,除非你在其他地方释放它。UIImageView.initWithImage:会保留图像。 - fishinear

0
你在Snow Leopard上使用Xcode 3.1吗?我也遇到了同样的问题:
CGContextRef ctx = ...;
CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
UIImage * newImage = [[UIImage imageWithCGImage:cgImage] retain];

CGImageRelease(cgImage); // this should be OK, but it now crashes in Simulator on SL

我猜升级到Xcode 3.2会解决这个问题。

从Xcode 8.1开始,这对我有效。如果我不释放CGImage,就会出现内存泄漏,所以我认为这是正确的做法。 - Adam Evans

0

<>不是我的观点。我也遇到了同样的问题。根据文档

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

imho 保持所有引用正确。如果您正在使用 CGDataProvider,请查看 CGDataProviderReleaseDataCallback, 并在回调中设置断点。您可以看到在您 [release] 图像后它被正确调用,您可以在那里释放()您的图像数据缓冲区。


0
"This method does not cache the image object."

因此UIImage拥有所有权,因此您不应该释放CGImageRef。


0

我同意你的看法 - 就这个API而言,文档最好也只是含糊不清。基于你的经验,我得出结论,你需要负责两个对象的生命周期 - UIImageCGImageRef。此外,你还需要确保CGImageRef的寿命至少和UIImage一样长(出于明显的原因)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接