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;
}
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;
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:
- 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.
- Wrap the
CGImageRef
in an autoreleased UIImage
object and return that ([UIImage imageWithCGImage:]
). That's probably what I would do.
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.
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.