开发者

EXC_BAD_ACCESS on calling drawRect on a retained UIImage

开发者 https://www.devze.com 2023-04-08 15:08 出处:网络
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.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消