How do I release a CGImageRef in iOS
Your memory issue results from the copied data, as others have stated. But here's another idea: Use Core Graphics's optimized pixel interpolation to calculate the average.
- Create a 1x1 bitmap context.
- Set the interpolation quality to medium (see later).
- Draw your image scaled down to exactly this one pixel.
- Read the RGB value from the context's buffer.
- (Release the context, of course.)
This might result in better performance because Core Graphics is highly optimized and might even use the GPU for the downscaling.
Testing showed that medium quality seems to interpolate pixels by taking the average of color values. That's what we want here.
Worth a try, at least.
Edit: OK, this idea seemed too interesting not to try. So here's an example project showing the difference. Below measurements were taken with the contained 512x512 test image, but you can change the image if you want.
It takes about 12.2 ms to calculate the average by iterating over all pixels in the image data. The draw-to-one-pixel approach takes 3 ms, so it's roughly 4 times faster. It seems to produce the same results when using kCGInterpolationQualityMedium
.
I assume that the huge performance gain is a result from Quartz noticing that it does not have to decompress the JPEG fully but that it can use the lower frequency parts of the DCT only. That's an interesting optimization strategy when composing JPEG compressed pixels with a scale below 0.5. But I'm only guessing here.
Interestingly, when using your method, 70% of the time is spent in CGDataProviderCopyData
and only 30% in the pixel data traversal. This hints to a lot of time spent in JPEG decompression.
Note: Here's a late follow up on the example image above.
Releasing CGImage (CGImageRef)
Core Foundation objects (which all Core Graphics objects are) do support autorelease.
The steps you describe should work just fine and not leak or over-release the object.
I use CFRelease
instead of specific-class release functions like CGImageRelease
, but purely as a matter of style. I just have to beware of NULL
: CGImageRelease
checks for NULL
, whereas CFRelease
will crash when passed NULL
. Using CGImageRelease
and its siblings means you don't have to worry about this.
I'm assuming you meant removeObject:forKey:
, not removeObject
(which doesn't exist and wouldn't have somewhere to specify an object anyway).
How to release CGImageRef if required to return it?
The Cocoa memory management naming policy states, that you own an object that is created from methods whose name begin with alloc, copy or new.
This rules are also respected by the Clang Static Analyzer.
Note that there are slightly different conventions for Core Foundation. Details can be found in Apple's Advanced Memory Management Programming Guide.
I modified your above method to conform to that naming conventions. I also removed the asterisk when passing in anImage
, as CGImageRef
is already a pointer. (Or was this on purpose?).
Note that you own the returned CGImage
and have to CGImageRelease
it later.
-(CGImageRef)newResizedImageWithImage:(CGImageRef)anImage width:(CGFloat)width height:(CGFloat)height
{
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(anImage);
if (alphaInfo == kCGImageAlphaNone)
{
alphaInfo = kCGImageAlphaNoneSkipLast;
}
CGContextRef bitmap = CGBitmapContextCreate(NULL, width, height, CGImageGetBitsPerComponent(anImage), 4 * width, CGImageGetColorSpace(anImage), alphaInfo);
CGContextDrawImage(bitmap, CGRectMake(0, 0, width, height), anImage);
CGImageRef image = CGBitmapContextCreateImage(bitmap);
CGContextRelease(bitmap);
return image;
}
When is it appropriate to release CGImageRef?
UIImageView retains the image property (if it needs it) or it copies it - whatever. Once you have set that property, you can then immediately release the CGImageRef.
How do I release a CGDataProvider in Swift on iOS?
You don't have to release it. The documentation is still targeted towards Objective-C. The compiler error message is correct.
From Using Swift with Cocoa and Objective-C:
Core Foundation objects returned from annotated APIs are automatically memory managed in Swift—you do not need to invoke the
CFRetain
,CFRelease
, orCFAutorelease
functions yourself.
Need to release a CGImage contained in a CALayer's contents property
The contents
property on CALayer
is a retaining property, meaning that it's setter implementation more or less does this:
- (void)setContents:(id)contents
{
if (contents == _contents) return; // Same as existing value
[_contents release];
_contents = [contents retain];
}
So, when you set nil
as the new contents, the old contents is released.
Related Topics
In iPhone App How to Detect the Screen Resolution of the Device
How to Change Locale Programmatically with Swift
Tablefooterview Property Doesn't Fix the Footer at the Bottom of the Table View
iOS 7 - Difference Between Viewdidload and Viewdidappear
Using Iskindofclass with Swift
How to Detect If a Video File Was Recorded in Portrait Orientation, or Landscape in iOS
How to Opt Your iPad App Out of Multitasking on iOS 9
No Umbrella Header Found for Target, Module Map Will Not Be Generated
iOS 9 Facebook Login Simulator -Canopenurl: Failed for Url: "Fbauth2:///" - Error: "(Null)"
Swift Different Images For Annotation
Why Do We Use Use_Frameworks! in Cocoapods
iOS 7 Sprite Kit Freeing Up Memory
"From View Controller" Disappears Using Uiviewcontrollercontexttransitioning
Module Compiled with Swift 5.1 Cannot Be Imported by the Swift 5.1.2 Compiler
Navigationlink Works Only for Once
In iOS, How to Store a Secret "Key" That Will Allow Me to Communicate with My Server