Xcode Analyzer在内存泄漏和ARC不正确的减少时发出问题

时间:2017-03-10 05:55:59

标签: ios objective-c xcode memory-leaks

我在我的项目中使用ARC,但是当我运行Analyzer时,我遇到了以下问题。

enter image description here

enter image description here

以下是我的代码: -

#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

如何才能使其正确? 请帮助我理解这个问题意味着什么以及为什么会发生这种情况,因为我曾经认为ARC会自行处理所有内存清理问题。还有其他SO问题,因为错误几乎与此相同。但不是CGContextRef。所以我不得不问一个新问题。

1 个答案:

答案 0 :(得分:1)

ARC仅处理对象指针类型和块指针类型。它不处理Core Foundation风格的引用类型(例如CGContextRef)。

现在到了分析仪问题。分析器(类似于ARC)注重命名约定,以确定方法或函数的行为方式。对于方法或函数的实现,它然后检查它是否确实按照其命名约定运行。在呼叫站点,它假定它,然后检查周围的代码是否按照该假设运行。

现在,您可能知道Core Foundation有"Create Rule",其中名称包含“Create”或“Copy”的函数通常返回+1引用,而其他函数通常返回+0引用(“获取规则“)。也许这就是你为自己的方法命名的原因,该方法在其名称中返回CGContext并带有“create”。不幸的是,Core Foundation规则不适用于Objective-C方法。

Cocoa命名约定是名称以“alloc”,“new”,“copy”或“mutableCopy”开头的方法返回+1引用。 (如果您没有使用ARC,release方法也会返回+1引用。)其他方法返回+0引用。

根据Cocoa命名约定,假设您的-createARGBBitmapContextFromImage:方法返回+0引用。但是,实际实现返回+1引用。这是分析仪报告的问题之一。然后,在呼叫站点,假设呼叫代码接收+0参考。因此,它无权使用CGContextRelease()发布该引用。这是分析仪报告的另一个问题。

您可以通过将-createARGBBitmapContextFromImage:重命名为-newARGBBitmapContextFromImage:来解决此问题。然后,根据Cocoa约定,它将返回+1引用,并且实现和调用站点都符合此期望。

或者,您可以-createARGBBitmapContextFromImage:执行return (CGContextRef)CFAutorelease(context);而不只是return context;。然后更改调用方以不尝试释放上下文。在这种情况下,方法的名称表示它返回+0引用,同样,实现和调用站点都符合这一点。