【问题标题】:Xcode Analyzer issue on memory leak and incorrect decrement with ARCXcode Analyzer 的内存泄漏问题和 ARC 错误减量
【发布时间】:2017-07-31 09:03:33
【问题描述】:

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

和

以下是我的代码:-

#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 自己处理所有内存清理问题。还有其他关于错误的问题几乎与此相同。但不在 CGContextRef 上。所以我不得不问一个新问题。

【问题讨论】:

    标签: ios objective-c xcode memory-leaks


    【解决方案1】:

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

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

    现在,您可能知道 Core Foundation 有 "Create Rule",其中名称包含“创建”或“复制”的函数通常返回 +1 引用,而其他函数通常返回 +0 引用(“获取规则”)。也许这就是为什么您将您的方法命名为返回名称中带有“create”的CGContext 的原因。不幸的是,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 引用,同样,实现和调用站点都符合该引用。

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 2012-04-03
    • 2012-09-14
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多