我正在为一个更复杂的项目尝试一个简单的测试但我感到困惑的是为什么下面的代码崩溃并给出一个EXC_BAD_ACCESS错误?
这是从UIView调用的。
- (void)testing {
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"ball.png" ofType:nil];
CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage];
// CGImageRetain(imageRef);
UIImage *newImage = [[UIImage alloc]initWithCGImage:imageRef];
UIImageView *iv = [[UIImageView alloc]initWithImage:newImage];
[self addSubview:iv];
}
我的猜测是CGImageRef没有被保留但是添加了CGImageRetain(imageRef);没有区别。
我还应该注意到这个项目已经启用了ARC。
编辑
我做了一些测试,并发现这与ARC直接相关,因为我创建了2个基本项目,仅包括上面的代码。 ARC的第一个关闭,它完美地工作。 ARC的下一个打开,BAM崩溃并出现同样的错误。有趣的是,我在崩溃前第一次运行项目时遇到了实际的日志错误。
Error: ImageIO: ImageProviderCopyImageBlockSetCallback 'ImageProviderCopyImageBlockSetCallback' header is not a CFDictionary...
答案 0 :(得分:11)
这一行是问题所在:
CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage];
创建的UIImage
将在此完整表达后立即释放(例如,在此行之后)。因此,即使尝试在之后添加CGImageRetain()
也行不通。
根本问题是从CGImageRef
返回的CGImage
几乎肯定是UIImage
的ivar,并且会在UIImage
被解除分配时释放。
解决此问题的一般方法是延长UIImage
的生命周期。您可以将UIImage
放入本地变量并在上次引用CGImage
后引用它(例如使用(void)uiimageVar
)来执行此操作。或者,您可以将CGImageRef
保留在同一行,例如
CGImageRef imageRef = CGImageRetain([[[UIImage alloc] initWithContentsOfFile:imagePath] CGImage]);
但如果你这样做,请不要忘记在完成后释放imageRef
。
答案 1 :(得分:5)
你写了这个:
CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage];
该行创建UIImage
,获取其CGImage
属性,然后释放UIImage
对象。由于您未在该行上保留CGImage
,因此CGImage
的唯一所有者是UIImage
。因此,当UIImage
被释放并立即解除分配时,它也会释放CGImage
。
您需要在CGImage
发布之前保留UIImage
。试试这个:
CGImageRef imageRef = CGImageRetain([[UIImage alloc]initWithContentsOfFile:imagePath].CGImage);
然后在函数结束时:
CGImageRelease(imageRef);