我在我的项目中使用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会自行处理所有内存清理问题。还有其他SO问题,因为错误几乎与此相同。但不是CGContextRef。所以我不得不问一个新问题。
答案 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引用,同样,实现和调用站点都符合这一点。