是什么导致块不能在ARC下保留引用的Objective-C对象?

时间:2013-02-08 00:16:57

标签: objective-c automatic-ref-counting objective-c-blocks

我收到一份崩溃报告说:

  

***由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [__ NSMallocBlock__ CGImage]:无法识别的选择器发送到实例0x1fb17f90'

这通常发生在一个对象被解除分配并且另一个对象现在与解除分配的对象位于同一地址时。

这是我的代码(我的应用中唯一一个我调用CGImage方法的地方):

@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

我认为image对象应该由块自动保留(我正在使用ARC),这样在使用它的代码执行之前,image对象无法解除分配。默认优先级队列。崩溃似乎意味着它没有被保留。

我的假设错了还是我错过了其他的东西?

2 个答案:

答案 0 :(得分:2)

这与ARC下的UIColor和CGColorRef的行为类似吗?正如这里详述:http://blog.bignerdranch.com/296-arc-gotcha-unexpectedly-short-lifetimes/

所以你在哪里:

CGImageRef imageRef = [image CGImage];

我认为你需要在块中明确地保留它,然后明确地释放它,这样ARC就不会释放图像引用。

所以:

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

答案 1 :(得分:0)

您的块本身可能没有问题。有人叫这个街区;调用者可能已经传递了一个解除分配的对象。我会在块的第一行中执行NSLog(@“%@”,image),并查看调用代码。