【问题标题】:iOS: UIImage EXC_BAD_ACCESSiOS:UIImage EXC_BAD_ACCESS
【发布时间】:2013-02-03 17:09:49
【问题描述】:

我正在构建一个仅适用于 iPhone 的小型应用程序 (iOS SDK 6.0),我在 XCode 中遇到 EXC_BAD_ACCESS 异常。

应用程序有UITableView 和自定义UITableViewCell。我在一个子类中实现了UITableViewCell(这里我称之为MyCustomCell)并向构造函数添加了另一个参数:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier cellImage:(UIImage *)image;

UIImage添加到方法中TableCellcontentView,代码如下:

imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
imageView.image = image;

[self.contentView addSubview:imageView];

这个函数当然是在函数cellForRowAtIndexPath内部调用的:

static NSString *CellIdentifier = @"MyCustomCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil)
{
    cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier cellImage:self.cellImage] autorelease];
}

return cell;

ViewController(也是UITableViewDelegate)的cellImage 属性声明为(它也是合成的):

@property (nonatomic, retain) UIImage* cellImage;

图像在 ViewController 的viewWillAppear 方法中初始化,代码如下:

cellImage = [UIImage imageNamed:@"my_image_resource.png"];

此代码可以正常工作,但是当我使用 iOS 6.0 唯一功能自定义图像时出现 EXC_BAD_ACCESS

cellImage = [[UIImage imageNamed:@"my_image_resource.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10) resizingMode:UIImageResizingModeStretch];

调试帮助我找到了触发错误的行 - 它位于 MyCustomCell 实现的 initWithStyle 方法中:

imageView.image = image;

我已经查看了许多EXC_BAD_ACCESS 错误,我还阅读了为什么会出现此错误的教程,但到目前为止,我并没有取消分配任何东西。此时可能会释放一些对象,但我无法准确找到哪个对象以及如何解决问题。

我还尝试在 ViewController 类中创建两个属性,一个用于保存原始图像,另一个用于保存插图。然而,它并没有解决问题。

为什么这是一个错误?为什么它不适用于带有插图的图像?我该如何解决这个问题?

谢谢。

【问题讨论】:

    标签: iphone ios objective-c memory-management


    【解决方案1】:

    执行imageView.image = image;语句时出现错误。因此,执行此语句时,对象image 不存在。它必须在之前发布过,或者通过[release image] 显式发布(因为您不使用ARC),或者如果image 是自动发布的(例如,如果您使用[UIImage imageNamed:...] 创建它)。
    正如 Aaron Wojnowski 建议的那样,我认为最好的方法是转换您的代码 ARC。否则,检查image是否会被意外释放。

    【讨论】:

    • 图像在任何地方都没有定义为自动释放,所以我假设默认是保留?我不会在任何地方明确发布图像。
    • 但是可以隐式定义为自动释放,例如正如我在回答中提到的那样,使用 [UIImage imageNamed:...] 。那么,你是如何声明图像的呢?使用 [UIImage alloc],它会保留它,或者例如使用 [UIImage imageNamed:...],它会将其放入当前的自动释放池中吗?
    • 您可以在问题中看到,它是用 imageNamed 声明的,我只是不确定从哪里可以得到这些信息?我似乎在 Apple 开发网站上找不到它:developer.apple.com/library/ios/#documentation/uikit/reference/…d
    • 你是对的,在你的代码中“image”是用“imageNamed:”声明的。它是一个根据 Cocoa 内存管理规则的自动释放对象,正如 stackoverflow.com/questions/1378206/…> 中指出的那样。
    【解决方案2】:

    您已经为 cellImage 创建了一个属性,但是您使用实例变量而不是为您创建的 setter 来设置它。由于您传递的是一个自动释放的对象,因此当您下次尝试引用它时,它可能已被释放。试试下面这个:

    [self setCellImage:[[UIImage imageNamed:@"my_image_resource.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10) resizingMode:UIImageResizingModeStretch]];
    

    或者用这个:

    self.cellImage = [[UIImage imageNamed:@"my_image_resource.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10) resizingMode:UIImageResizingModeStretch];
    

    使用此代码,图像将在 setter 中为您保留,下次您尝试使用它时,内存仍将被分配,您应该不会有任何问题。

    如果可能,还可以考虑使用 ARC,因为这些复杂的内存管理工作都会为您处理。 http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

    【讨论】:

    • 就逻辑而言,您是正确的。我仍然习惯于 Objective-C 的动态类型。实例变量显然是在之后的某个时间释放的。但是,它仍然没有解释为什么没有发生这种情况,如果图像没有设置插图。关于ARC,我知道,但这是一个学习项目,我想详细学习内存管理,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-19
    • 2018-01-13
    • 2012-07-24
    • 2012-02-20
    • 1970-01-01
    相关资源
    最近更新 更多