Pawan Joshi
Pawan Joshi

Reputation: 1579

Xcode Analyzer issue on memory leak and incorrect decrement with ARC

I am Using ARC in my project but still when i ran Analyser i got following issues.

enter image description here

And

enter image description here

Following is my code :-

#import "UIImage+ImageSize.h"

@implementation UIImage (ImageSize)

- (CGRect)cropRectForImage:(UIImage *)image {

    CGImageRef cgImage = image.CGImage;
    CGContextRef context = [self createARGBBitmapContextFromImage:cgImage];
    if (context == NULL) return CGRectZero;

    size_t width = CGImageGetWidth(cgImage);
    size_t height = CGImageGetHeight(cgImage);
    CGRect rect = CGRectMake(0, 0, width, height);

    CGContextDrawImage(context, rect, cgImage);

    unsigned char *data = CGBitmapContextGetData(context);
    CGContextRelease(context);

    //Filter through data and look for non-transparent pixels.
    int lowX = (int)width;
    int lowY = (int)height;
    int highX = 0;
    int highY = 0;
    if (data != NULL) {
        for (int y=0; y<height; y++) {
            for (int x=0; x<width; x++) {
                int pixelIndex = (int)(width * y + x) * 4 /* 4 for A, R, G, B */;
                if (data[pixelIndex] != 0) { //Alpha value is not zero; pixel is not transparent.
                    if (x < lowX) lowX = x;
                    if (x > highX) highX = x;
                    if (y < lowY) lowY = y;
                    if (y > highY) highY = y;
                }
            }
        }
        free(data);
    } else {
        return CGRectZero;
    }

    return CGRectMake(lowX, lowY, highX-lowX, highY-lowY);
}
- (CGContextRef)createARGBBitmapContextFromImage:(CGImageRef)inImage {

    CGContextRef context = NULL;
    CGColorSpaceRef colorSpace;
    void *bitmapData;
    int bitmapByteCount;
    int bitmapBytesPerRow;

    // Get image width, height. We'll use the entire image.
    size_t width = CGImageGetWidth(inImage);
    size_t height = CGImageGetHeight(inImage);

    // Declare the number of bytes per row. Each pixel in the bitmap in this
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and
    // alpha.
    bitmapBytesPerRow = (int)(width * 4);
    bitmapByteCount = (int)(bitmapBytesPerRow * height);

    // Use the generic RGB color space.
    colorSpace = CGColorSpaceCreateDeviceRGB();
    if (colorSpace == NULL) return NULL;

    // Allocate memory for image data. This is the destination in memory
    // where any drawing to the bitmap context will be rendered.
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL)
    {
        CGColorSpaceRelease(colorSpace);
        return NULL;
    }

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
    // per component. Regardless of what the source image format is
    // (CMYK, Grayscale, and so on) it will be converted over to the format
    // specified here by CGBitmapContextCreate.
    context = CGBitmapContextCreate (bitmapData,
                                     width,
                                     height,
                                     8,      // bits per component
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst);
    if (context == NULL) free (bitmapData);

    // Make sure and release colorspace before returning
    CGColorSpaceRelease(colorSpace);
    return context;
}

@end

How can i make it correct ? Please help me understand what does this issue means and why this is happening, because i used to think ARC handles all memory clean up issues by it self. there are other SO questions already asked on error almost same as this. but not on CGContextRef. so i had to ask a new question.

Upvotes: 2

Views: 107

Answers (1)

Ken Thomases
Ken Thomases

Reputation: 90621

ARC only handles object pointer types and block pointer types. It does not handle Core Foundation-style reference types (e.g. CGContextRef).

Now to the analyzer issue. The analyzer (similar to ARC) pays attention to naming conventions to determine how a method or function is assumed to behave. For the implementation of the method or function, it then checks if it actually does behave in accordance to its naming convention. At call sites, it assumes it does and then checks that the surrounding code operates in accordance with that assumption.

Now, you may be aware that Core Foundation has the "Create Rule" where functions whose names contain "Create" or "Copy" generally return a +1 reference, while other functions generally return a +0 reference (the "Get Rule"). Maybe that's why you named the your method which returns a CGContext with "create" in its name. Unfortunately, the Core Foundation rules don't apply to Objective-C methods.

The Cocoa naming conventions are that methods whose names begin with "alloc", "new", "copy", or "mutableCopy" return a +1 reference. (If you weren't using ARC, the release method also returns a +1 reference.) Other methods return a +0 reference.

By the Cocoa naming conventions, your -createARGBBitmapContextFromImage: method is assumed to return a +0 reference. But, the actual implementation returns a +1 reference. That's one of the issues the analyzer reported. Then, at the call site, the calling code is assumed to receive a +0 reference. Therefore, it's not entitled to release that reference using CGContextRelease(). That's the other issue the analyzer is reporting.

You can fix this by renaming -createARGBBitmapContextFromImage: to -newARGBBitmapContextFromImage:. Then, by the Cocoa conventions, it would be expected to return a +1 reference and both the implementation and the call site would conform to this expectation.

Alternatively, you can have -createARGBBitmapContextFromImage: do return (CGContextRef)CFAutorelease(context); instead of just return context;. Then change the caller to not attempt to release the context. In this case, the method's name indicates it returns a +0 reference and, again, the implementation and call site both conform to that.

Upvotes: 1

Related Questions