7

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;     
}
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
Louis de Decker
  • 525
  • 1
  • 7
  • 14
  • I had a similar leak. Try my answer here: http://stackoverflow.com/a/23669476/3631310 – Vlad May 15 '14 at 06:46

4 Answers4

16

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;
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
11

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.
Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
3

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.

shem
  • 4,686
  • 2
  • 32
  • 43
3

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.

Jonathan Grynspan
  • 43,286
  • 8
  • 74
  • 104