EXC_BAD_ACCESS on calling drawRect on a retained UIImage
I have a bit of a weird problem. I create a UIImage with imageNamed extract colour data from it and then set it to another class.
Then from that class when I do a drawRect I get an EXC_BAD_ACCESS when doing the drawRect.
Here is where I load the image:
UIImage* pImageHM = [UIImage imageNamed:@"Heatmap2.png"];
CGIm开发者_如何学PythonageRef 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 );
The SetScale function is defined as follows:
- (void) SetScale: (UIImage*)pImage
{
[mpScale release];
mpScale = pImage;
[mpScale retain];
[self setNeedsDisplay];
}
And finally I render it as follows:
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 );
Why would the mpScale raise an EXC_BAD_ACCESS? Given the UIImage has been retained the fact it was subsequently autoreleased after I had called SetScale should be neither here nor there.
I should add that if I don't call SetScale (such that mpScale remains as nil) then I get no crash and, obviously, I don't see anything where the scale ought to be.
Thanks in advance!
CGImageRef irHM = [pImageHM CGImage];
You do not own this CGImage, but you are releasing it.
CGImageRelease( irHM );
You have multiple problems here:
Your SetScale method does not follow Cocoa naming conventions (see here). Call it
setScale
with a lowercase "set" prefix, for it to be considered as a setter (and hence allow KVC to work, dot-notation to work automatically, etc)You have to check that mpImage and pImage are not the same object when implementing the setScale setter. If you don't you will end up with an EXC_BAD_ACCESS (maybe the one you have, then) because you will release the object before affecting+retaining it so it will reach a retainCount of zero before you have a chance to retain it again.
Your setter should be:
-(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
}
}
Moreover (and this is the real reason of your EXC_BAD_ACCESS), you are releasing irHM
(CGImageRelease
on the last line of your code) but you shouldn't (you didn't retain it or take ownership of it before)
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 !!
In the event pImage == mpScale
, when you call SetScale
you will release the image, set it, then retain nothing. mpScale
at that point will be pointing to an invalid object.
精彩评论