Louis de Decker
Louis de Decker

Reputation: 522

CGImageRef Memory leak

I'm having a memory leak when using this custom method which returns a CGImageRef. I can't release "cgImage" properly because I have to return it. What chould I do ?

- (CGImageRef)rectRoundedImageRef:(CGRect)rect radius:(int)radius
{
    CGSize contextSize = CGSizeMake(rect.size.width, rect.size.height);     
    CGFloat imageScale = (CGFloat)1.0;
    CGFloat width = contextSize.width;
    CGFloat height = contextSize.height;        
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, width * imageScale, height * imageScale, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
    // Draw ...
    // Get your image
    CGImageRef cgImage = CGBitmapContextCreateImage(context);       
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(context);
    //CGImageRelease(cgImage); //If I release cgImage the app crashes.
    return cgImage;     
}

Upvotes: 7

Views: 10159

Answers (4)

shem
shem

Reputation: 4712

As suggested, we used:

CGImageRelease(imageRef);

but we still got an memory leak. our solution was to wrap code with an

@autoreleasepool {}

block and that solve our problem.

Upvotes: 3

Jonathan Grynspan
Jonathan Grynspan

Reputation: 43472

You can autorelease a Core Foundation-compatible object. it just looks a bit wonky. :)

The GC-safe way is like so:

CGImageRef image = ...;
if (image) {
    image = (CGImageRef)[[(id)image retain] autorelease];
    CGImageRelease(image);
}

The shortcut, which is safe on iOS but no longer safe on the Mac, is this:

CGImageRef image = ...;
if (image) {
    image = (CGImageRef)[(id)image autorelease];
}

Either one will place the image in an autorelease pool and prevent a leak.

Upvotes: 3

Jacob Relkin
Jacob Relkin

Reputation: 163308

cgImage is owned by your method, you need to return it and give responsibility to the caller to release it through CFRelease.

You can also return the CGImage wrapped inside a UIImage instance, like this:

UIImage *image = [UIImage imageWithCGImage:cgImage];
CFRelease(cgImage); //cgImage is retained by the UIImage above
return image;

Upvotes: 16

Ole Begemann
Ole Begemann

Reputation: 135588

This is a general problem with Core Foundation objects because there is no autorelease pool in CF. As I see it, you have two options to solve the problem:

  1. Rename the method to something like -newRectRoundedImageRef:radius: to tell the caller that he takes ownership of the returned object and responsible for releasing it.
  2. Wrap the CGImageRef in an autoreleased UIImage object and return that ([UIImage imageWithCGImage:]). That's probably what I would do.

Upvotes: 11

Related Questions