5

我正在为一个更复杂的项目尝试一个简单的测试,但我很困惑为什么下面的代码会崩溃并给出 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...
4

2 回答 2

13

这条线是问题所在:

CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage];

createdUIImage将在此完整表达式之后立即释放(例如,在此行之后)。因此,即使尝试在CGImageRetain()之后添加一个也行不通。

根本问题是CGImageRef返回的 fromCGImage几乎可以肯定是 the 的一个 ivar,UIImage并且在解除分配时将被释放UIImage

解决此问题的通用方法是延长UIImage. 您可以通过将UIImage放入局部变量并在最后一次引用之后引用它CGImage(例如,使用(void)uiimageVar)来完成此操作。或者,您可以将 保留CGImageRef在同一行,如

CGImageRef imageRef = CGImageRetain([[[UIImage alloc] initWithContentsOfFile:imagePath] CGImage]);

但是如果你这样做了,别忘了imageRef在你完成后释放。

于 2012-10-06T03:11:12.490 回答
5

你写了这个:

CGImageRef imageRef = [[[UIImage alloc]initWithContentsOfFile:imagePath]CGImage];

该行创建一个UIImage,获取其CGImage属性,然后释放该UIImage对象。由于您没有保留该CGImage行上的 ,因此唯一的所有者CGImageUIImage. 因此,当UIImage释放并立即释放时,它也释放了CGImage

您需要在发布CGImage之前保留UIImage。试试这个:

CGImageRef imageRef = CGImageRetain([[UIImage alloc]initWithContentsOfFile:imagePath].CGImage);

然后在函数结束时:

CGImageRelease(imageRef);
于 2012-10-06T03:10:37.767 回答