简体   繁体   中英

What can cause a block to not retain a referenced Objective-C object under ARC?

I have received a crash report saying this:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSMallocBlock__ CGImage]: unrecognized selector sent to instance 0x1fb17f90'

This typically happens when an object has been deallocated and another object now lives at the same address as the deallocated object.

Here is my code (the only place in my app where I'm calling the CGImage method):

@implementation UIImageView (MyApp)

- (void) setImageWithObject:(id)object
{
    NSURLRequest *imageRequest = [NSURLRequest requestWithURL:[object URL]];
    __typeof__(self) __weak weakSelf = self;
    [self setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            CGImageRef imageRef = [image CGImage];
            CGRect rect = CGRectMake(0.f, 0.f, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
            CGContextRef bitmapContext = CGBitmapContextCreate(NULL, (size_t)roundf(CGRectGetWidth(rect)), (size_t)roundf(CGRectGetHeight(rect)), CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), CGImageGetColorSpace(imageRef), CGImageGetBitmapInfo(imageRef));
            UIImage *decompressedImage = image;
            if (bitmapContext)
            {
                CGContextDrawImage(bitmapContext, rect, imageRef);
                CGImageRef decompressedImageRef = CGBitmapContextCreateImage(bitmapContext);
                decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation];
                CGImageRelease(decompressedImageRef);
                CGContextRelease(bitmapContext);
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                weakSelf.image = decompressedImage;
            });
        });
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
        NSLog(@"%@", error);
    }];
}

@end

I assumed that the image object should be automatically retained by the block (I'm using ARC) so that the image object can't be deallocated before the code using it is executed on the default priority queue. The crash seems to imply that it was not retained.

Is my assumption wrong or am I missing something else?

Isn't this similar to the behaviour as with the UIColor and CGColorRef under ARC? As elaborated here: http://blog.bignerdranch.com/296-arc-gotcha-unexpectedly-short-lifetimes/

So where you have:

CGImageRef imageRef = [image CGImage];

I think you need to retain it explicitly within the block and then release it explicitly so ARC does't deallocate the image ref.

So:

CGImageRef imageRef = CGImageRetain([image CGImage]);
...
CGImageRelease(imageRef);

There may be no problem in your block itself. Someone calls the block; it would be possible that the caller already passed a deallocated object. I'd do an NSLog (@"%@", image) in the first line of the block and also look at the calling code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM