【问题标题】:imageWithCGImage and memoryimageWithCG图像和内存
【发布时间】:2025-12-06 02:30:01
【问题描述】:

如果我使用[UIImage imageWithCGImage:],传入CGImageRef,然后释放CGImageRef 还是UIImage 在释放时自行处理?

文档并不完全清楚。它说“此方法不缓存图像对象。”

最初我在将 CGImageRef 传递给imageWithCGImage: 后调用了CGImageRelease,但这导致模拟器中出现malloc_error_break 警告,声称正在发生双释放。

【问题讨论】:

标签: cocoa-touch core-graphics


【解决方案1】:

根据fundamental rule of Cocoa memory management,拥有对象应在不再需要时释放拥有的对象。其他对象负责自行获取和释放所有权。如果UIImage 需要一个对象来持久化但不保留或复制它,这是UIImage 的实现中的一个错误,应该这样报告。

【讨论】:

    【解决方案2】:

    我在 Snow Leopard 上的 XCode 3.2.1 中遇到了同样的问题。我的代码与 Jason 几乎相同。

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

    那么,这是模拟器中的错误吗?当我使用CGImageRelease 时,我总是在控制台上收到malloc_error_break 警告。

    【讨论】:

    • 这应该是对 Jason 的回答的评论,或者是一个新问题,因为 SO 不是论坛。
    • 我无法评论其他人的帖子,因为我没有足够的“声誉”。此外,这不是一个新问题。我只是建议问题可能只发生在模拟器中,而不是设备上。
    【解决方案3】:

    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不能保证与传入init方法的CGImage相同,所以类单独存储CGImage

    【讨论】:

      【解决方案4】:

      我同意你的看法——这个 API 的文档充其量是混乱的。那么,根据您的经验,我会得出结论,您应对两个对象的生命周期负责 - UIImageCGImageRef。最重要的是,您必须确保 CGImageRef 的生命周期至少与 UIImage 一样长(原因很明显)。

      【讨论】:

        【解决方案5】:

        您是否在 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,我会发生内存泄漏,所以我认为这是这样做的方法。
        【解决方案6】:

        不确定这是否有帮助,但我遇到了类似的问题。 我阅读了答案,然后做了以下似乎已经解决的问题:

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

        我按照建议使用了自动释放,但这还不够。 我已将图像添加到 UIImageView 中,然后发布了 cgImage。
        它没有崩溃并且很好地释放了。为什么——我不知道,但它奏效了。

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

        【讨论】:

        • 似乎您在这里泄漏了 thumbImage,除非您在其他地方发布它。 UIImageView.initWithImage:会保留图片。
        【解决方案7】:

        不是我的意见。我有同样的问题。根据文档

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

        恕我直言,所有参考资料均正确无误。如果您使用的是 CGDataProvider,请查看 CGDataProviderReleaseDataCallback 并在回调中设置断点。您可以看到在您 [release] 图像后正确调用了它,并且您可以在此处释放()您的图像数据缓冲区。

        【讨论】:

          【解决方案8】:
          "This method does not cache the image object."
          

          所以 UIImage 取得了所有权,因此你不应该释放 CGImageRef。

          【讨论】:

            最近更新 更多