我有一个奇怪的问题。我创建了一个带有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保持为零)那么我就不会崩溃,显然,我没有看到任何规模应该是什么。
提前致谢!
答案 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的真正原因),您将在代码的最后一行发布irHM
(CGImageRelease
),但您不应该(你之前没有保留或取得它的所有权)
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
将指向无效对象。