imageWithCGImage and memory
Asked Answered
P

8

17

If I use [UIImage imageWithCGImage:], passing in a CGImageRef, do I then release the CGImageRef or does UIImage take care of this itself when it is deallocated?

The documentation isn't entirely clear. It says "This method does not cache the image object."

Originally I called CGImageRelease on the CGImageRef after passing it to imageWithCGImage:, but that caused a malloc_error_break warning in the Simulator claiming a double-free was occurring.

Pola answered 9/9, 2009 at 21:16 Comment(1)
I suggest filing a documentation bug at bugreport.apple.com to ask them to clarify this.Fraga
D
0

I agree with you -- the documentation is muddled at best for this API. Based on your experiences, then, I would conclude that you are responsible for the lifetime of both objects - the UIImage and the CGImageRef. On top of that you have to make sure the lifetime of the CGImageRef is at least as long as the UIImage (for obvious reasons).

Dewayne answered 9/9, 2009 at 21:20 Comment(0)
E
8

According to the fundamental rule of Cocoa memory management, an owning object should release the owned object when it no longer needs it. Other objects are responsible for taking and releasing ownership on their own. If a UIImage needs an object to persist but doesn't retain or copy it, it's a bug in UIImage's implementation and should be reported as such.

Esmond answered 1/5, 2010 at 10:11 Comment(0)
C
4

I have the same problem in XCode 3.2.1 on Snow Leopard. I have pretty much the same code as Jason.

I have looked at the iPhone sample code which uses imageWithCGImage and they always release the CGImageRef using CGImageRelease after a call to imageWithCGImage.

So, is this a bug in the simulator? I always get the malloc_error_break warning on the console when I use CGImageRelease.

Cordeelia answered 15/3, 2010 at 14:52 Comment(2)
This should be a comment on Jason's answer, or a new question, as SO isn't a forum.Esmond
I can not comment other people's posts because I do not have enough "reputation". Besides, this isn't a new question. I simply suggested that the problem might only happen in the simulator but not on the device.Cordeelia
T
2

The ownership in UIImage about CGImage is unclear. It seems like don't copy the CGImage but it's not guaranteed by documentation. So we have to handle that ourselves.

I used a new subclass of UIImage to handle this problem. Just retaining passing CGImage, and releasing it when the dealloc.

Here is sample.

@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

Because the CGImage returned by -[UIImage CGImage] property is not guaranteed to be same CGImage passed into init method, the class stores CGImage separately.

Trying answered 21/4, 2011 at 5:44 Comment(0)
D
0

I agree with you -- the documentation is muddled at best for this API. Based on your experiences, then, I would conclude that you are responsible for the lifetime of both objects - the UIImage and the CGImageRef. On top of that you have to make sure the lifetime of the CGImageRef is at least as long as the UIImage (for obvious reasons).

Dewayne answered 9/9, 2009 at 21:20 Comment(0)
R
0

Are you using Xcode 3.1 on Snow Leopard? I am experiencing the same issue:

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

I'm guessing that upgrading to Xcode 3.2 will fix the issue.

Rambutan answered 21/9, 2009 at 11:4 Comment(1)
As of Xcode 8.1, this works for me. If I don't release the CGImage, I get a memory leak, so I assume this is the way to do it.Brittni
S
0

<> Not my opinion. I had the same problem. According to documentation

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

imho keeps all references correct. If you are using a CGDataProvider please have a look at CGDataProviderReleaseDataCallback and set a breakpoint in your callback. You can see that is is correctly called after you [release] your image and you can free() your image data buffer there.

Sulfapyridine answered 10/5, 2010 at 21:21 Comment(0)
V
0

Not sure if this helps, but I had a similar problem. I read the answers and then did the following which appears to have fixed it:

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

I used the autorelease as suggested but it was not enough. One I had added the image to the UIImageView I then released the cgImage.
It didn't crash and deallocated nicely. Why -- I have no idea but it worked.

The asset thumbnail part is from the ALAsset Library by the way, you might need something else there.

Vitellin answered 26/1, 2011 at 11:32 Comment(1)
Seems you are leaking thumbImage here, unless you release it elsewhere. UIImageView.initWithImage: will retain the image.Perichondrium
U
0
"This method does not cache the image object."

So the UIImage take the ownership, and thus you should not release the CGImageRef.

Union answered 24/9, 2016 at 14:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.