在保留的UIImage上调用drawRect的EXC_BAD_ACCESS

时间:2011-09-27 17:49:25

标签: iphone objective-c c uiimage cgcontext

我有一个奇怪的问题。我创建了一个带有imageNamed提取颜色数据的UIImage,然后将其设置为另一个类。

然后当我做drawRect时,从该类开始,我在执行drawRect时得到一个EXC_BAD_ACCESS。

这是我加载图片的地方:

UIImage*    pImageHM    = [UIImage imageNamed:@"Heatmap2.png"];
CGImageRef  irHM        = [pImageHM CGImage];
CFDataRef   drHM        = CGDataProviderCopyData( CGImageGetDataProvider( irHM ) );
R8G8B8A8*   pDataHM     = (R8G8B8A8*)CFDataGetBytePtr( drHM );

unsigned int colour     = 0;
unsigned int colourMax  = 256;
while( colour < colourMax )
{
    // Extract image data.
    colour++;
}
[mpView SetScale: pImageHM];

CFRelease( drHM );
CGImageRelease( irHM );

SetScale函数定义如下:

- (void) SetScale: (UIImage*)pImage
{
    [mpScale release];

    mpScale = pImage;

    [mpScale retain];

    [self setNeedsDisplay];
}

最后我将其渲染如下:

    CGContextRotateCTM( ctx, -M_PI_2 );
    CGContextTranslateCTM( ctx, -(rect.size.height - 48), 0);

    [mpScale drawInRect: CGRectMake( 0,                    rect.size.width - 16,
                                    rect.size.height - 48, 16 )];

    CGContextTranslateCTM( ctx, (rect.size.height - 48), 0 );
    CGContextRotateCTM( ctx, M_PI_2 );

为什么mpScale会引发EXC_BAD_ACCESS?鉴于UIImage已被保留,因此我在调用SetScale之后随后自动释放它应该既不在这里也不在那里。

我应该补充一点,如果我不调用SetScale(这样mpScale保持为零)那么我就不会崩溃,显然,我没有看到任何规模应该是什么。

提前致谢!

3 个答案:

答案 0 :(得分:4)

CGImageRef irHM = [pImageHM CGImage];

你没有这个CGImage,但你正在发布它。

CGImageRelease( irHM );

答案 1 :(得分:2)

这里有多个问题:

  • 您的SetScale方法不遵循Cocoa naming conventions (see here)。使用小写的“set”前缀将其称为setScale,因为它被视为一个setter(因此允许KVC工作,点符号自动工作等)

  • 实现setScale setter时,必须检查mpImage和pImage是否不是同一个对象。如果你不这样做,你最终会得到一个EXC_BAD_ACCESS(也许就是你拥有的那个)因为你会在影响+保留之前释放它,所以它会在你有机会再次保留之前达到retainCount零。

你的二传手应该是:

-(void)setScale:(UIImage*)pImage
{
    // only do this if the variables don't point to the same object in memory to avoid crash
    if (mpImage != pImage) {
        [mpImage release]; // release old value
        mpImage = [pImage retain]; // retain new one
    } 
}

此外(这是您的EXC_BAD_ACCESS的真正原因),您将在代码的最后一行发布irHMCGImageRelease),但您不应该(你之前没有保留或取得它的所有权)

CGImageRef  irHM        = [pImageHM CGImage];
CFDataRef   drHM        = CGDataProviderCopyData( CGImageGetDataProvider( irHM ) );
...
[mpView SetScale: pImageHM];

CFRelease( drHM ); // <-- that's ok because you did use a "...Copy..." method
// CGImageRelease( irHM ); // <-- you DON'T need nor should do that !!

答案 2 :(得分:1)

在事件pImage == mpScale中,当您致电SetScale时,您将释放图像,进行设置,然后不保留任何内容。此时mpScale将指向无效对象。