消息发送到解除分配的实例 - 简短而简单

时间:2011-09-30 05:22:14

标签: objective-c memory-management memory-leaks

这必须非常基础,但我没有看到问题。只要执行以下代码块,程序就会崩溃。 Analyzer报告可能的内存泄漏:

if (anImage) {
    eventImageView.frame = defaultEventImageFrame;
    UIImage *scaledImage = [anImage scaleToFitWithin:defaultEventImageFrame.size interpolationQuality:kCGInterpolationHigh];
    eventImageView.backgroundColor = [UIColor colorWithPatternImage:scaledImage];                
}

消息是 - [UIImage release]:发送到解除分配的实例0x1129d920的消息 *

实例0x1129d920是scaledImage

我尝试添加了保留和发布,就像这样

if (anImage) {
    eventImageView.frame = defaultEventImageFrame;
    UIImage *scaledImage = [[anImage scaleToFitWithin:defaultEventImageFrame.size interpolationQuality:kCGInterpolationHigh] retain];
    eventImageView.backgroundColor = [UIColor colorWithPatternImage:scaledImage];                
    [scaledImage release];        
}

仍然收到错误消息。

所以我尝试用副本替换作业,比如

if (anImage) {
    eventImageView.frame = defaultEventImageFrame;
    UIImage *scaledImage = [anImage copy];
    eventImageView.backgroundColor = [UIColor colorWithPatternImage:scaledImage];                
}

问题已经消失。

检查scaleToFitWithin方法,我看到它返回一个自动释放的对象:

- (UIImage *) scaleToFitWithin:(CGSize) newSize
          interpolationQuality:(CGInterpolationQuality)quality{

    CGSize originalImageSize = self.size;
    CGSize newImageSize;
    if (originalImageSize.width <= originalImageSize.height) {
        newImageSize.width = self.size.width * newSize.width  / self.size.width;
        newImageSize.height = self.size.height * newSize.width  / self.size.width;
    }
    else {
        newImageSize.width = self.size.width * newSize.height  / self.size.height;
        newImageSize.height = self.size.height * newSize.height  / self.size.height;        
    }
    return [[[self normalize] resizedImage:newImageSize interpolationQuality:kCGInterpolationHigh] autorelease];

}

所以有一些关于内存管理的东西,我不理解。可能是什么问题?

2 个答案:

答案 0 :(得分:1)

问题很可能是scaleToFitWithin:interpolationQuality:方法在之前已经autorelease d的对象上调用autorelease。如果您使用临时构造函数(如UIImage)初始化+[UIImage imageWith...],则可能会出现这种情况,这与您调用缩放方法的方法相同。使用[anImage copy]时它起作用的原因是因为copy构造函数的行为使得返回给您的对象已经调用retain(因此它具有本地保留)计数为1且为零autorelease s)。

当前运行循环结束时发生的情况是:当前正在使用的自动释放池已耗尽,并且作为这两条release消息的一部分将被发送到UIImage。发送第一个应用程序后,应用程序将运行并在图像上调用dealloc,因为retainCount已减少到零。当发送第二个时,应用程序抛出异常,因为正在将消息发送到先前已取消分配的对象。

尝试从autorelease方法中删除scaleToFitWithin:interpolationQuality:消息。即使您的resizedImage:interpolationQuality:方法正在返回对象,您也应该只在该方法中调用autorelease而不是缩放方法。

答案 1 :(得分:1)

似乎方法resizedImage:interpolationQuality:本身返回一个autoreleased对象,您再次在 reutun 语句中自动释放它。只需从 return 语句

中删除自动释放
return [[self normalize] resizedImage:newImageSize 
                 interpolationQuality:kCGInterpolationHigh];

然后您不必在if (anImage) {...}块中保留/释放复制返回的对象。