CGContextDrawImage - EXC_BAD_ACCESS和MapOverlayRenderer

时间:2015-01-09 17:13:25

标签: objective-c exc-bad-access

我有MapOverlayRenderer。有时,我在CGContextDrawImage

上获得了EXC_BAD_ACCESS

我的图像设定器方法来设置叠加图像

-(void)SetImageRef:(CGImageRef)imageRef
{       
    CGImageRelease(_imageReference);
    _imageReference = CGImageCreateCopy(imageRef);    
}

我的抽奖方法

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
    MKMapRect theMapRect = self.overlay.boundingMapRect;
    CGRect theRect = [self rectForMapRect:theMapRect];

    CGContextSetInterpolationQuality(context, self.interpolation);

    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextTranslateCTM(context, 0.0, -theRect.size.height);
    CGContextDrawImage(context, theRect, _imageReference); //<---- EXC_BAD_ACCESS

}

什么可能是错的,或者我该如何调试它。

如果我启用了Zombie Objects,崩溃就会消失,但调试控制台中也没有显示任何信息,所以我什么都不知道。

2 个答案:

答案 0 :(得分:3)

我怀疑您有时会将当前 _imageReference传递给SetImageRef:。您SetImageRef的实施并不能安全地处理这种情况。当您使用_imageReference发布CGImageRelease时,它将被取消分配(除非其他内容保留_imageReference,但听起来并非如此)。如果您随后复制:

_imageReference = CGImageCreateCopy(imageRef);

然后发生imageRef == _imageReference然后会发生什么?您最终得到_imageReference作为僵尸(或即将成为僵尸)图像的副本。现在,你正在复制,所以你可能认为imageRef正在死亡无关紧要(只要它在发布后没有被立即覆盖,尽管这仍然是不安全的代码),但有一个问题。 CGImageCreateCopy笔记的文档:

  

仅复制图像结构本身;该      基础数据不是。

因此_imageReference的“图像结构”数据可能是安全的,但_imageReference实际生成像素所需的数据安全。这就是为什么当你最终尝试使用CGContextDrawImage渲染图像时会遇到问题。

这是一个非常长篇大论的说法,你需要让SetImageRef更加小心。我建议您在imageRef == _imageReference

的特殊情况下尽早返回
-(void)SetImageRef:(CGImageRef)imageRef {
    if (imageRef == _imageReference) {
        return;
    }

    CGImageRelease(_imageReference);
    _imageReference = CGImageCreateCopy(imageRef);    
}

答案 1 :(得分:0)

我为OS X开发了Color Picker,当我使用两个物理显示器时也遇到了同样的问题。试着写你的自定义&#34; setImageRef&#34;为:

//Fix CGContextDrawImage Crash
-(void)SetImageRef:(CGImageRef)imgRef
{
    if (imgRef == _imageRef) return;
    CGImageRelease(_imageRef);
    _imageRef = CGImageCreateCopy(imgRef);
}

Aaron Golden对此问题有更详细的描述。