【问题标题】:Memory after recreated NSMutableArray reinitialized重新创建 NSMutableArray 后重新初始化的内存
【发布时间】:2011-10-19 17:41:24
【问题描述】:

我有一个类模仿UIImagePickerController 的行为,除了一些细微的差别。在我的课堂上,我只使用一个视图控制器,并在用户进行行/缩略图选择时使用它来交换相册表视图和照片表视图。所以导致我出现问题的事件顺序如下:

  1. 我选择相册
  2. 照片表格视图加载,我按下后退按钮返回 到专辑表格视图
  3. 相册表格视图加载
  4. 我选择了一个相册,现在触发内存访问错误

我已经在 ivars 中实现了 tableview 和数组,如下所示:

@property (nonatomic, retain) UITableView *selectAnAlbumTableView, *selectAPhotoTableView;
@property (nonatomic, retain) NSMutableArray *albums, *photos;
@property (nonatomic, retain) ALAssetsGroup *album;
@property (nonatomic, retain) UIActivityIndicatorView *spinner;

相册表格视图和照片表格视图之间的一个区别是,每次用户选择相册时都会重新创建照片表格视图,这就是发生错误的地方。最初,当我删除 tableview 时出现“EXC_BAD_ACCESS”,就像我在这里做的那样:

        [[self selectAPhotoTableView] removeFromSuperview];
        [selectAPhotoTableView release];
        selectAPhotoTableView = nil;
        [photos release];
         photos = nil;

我注意到错误发生在[photos release]。 Photos 是我存储放置在照片 tableview 上的单元格中的所有缩略图按钮的数组。如果我删除了[photos release] 和photos = nil,那么当实际创建tableview 时就会出现问题(正如我最初提到的那样):

NSMutableArray *photosTemp = [[NSMutableArray alloc] init];
[self setPhotos: photosTemp];
[photosTemp release];

现在“EXC_BAD_ACCESS”在[self setPhotos: photosTemp]; 行之后被抛出。有谁知道我在这里做错了什么?

更新:我在第二次出现错误的位置输入了错误的代码,现在已修复。

【问题讨论】:

  • 我们能看到错误吗?还有 ivars 的 @property 语句
  • @Max MacLeod 我已经在帖子中添加了您要求的内容。错误是“EXC_BAD_ACCESS”,上面列出了属性语句。感谢您的询问。
  • 能否启用僵尸并查看它是否会触发发送到已释放实例错误的消息?通过编辑你的方案在 xcode4 中启用僵尸,并选中诊断下的僵尸启用复选框
  • @MaxMacleod 嘿,Max,我按照您的要求做了,在控制台显示错误之前,我得到“2011-10-20 04:55:31.304 CustomImagePicker[21510:307] *** -[UIImage isKindOfClass:]: 消息发送到已释放实例 0x197850"
  • @MaxMacleod 谢谢这帮助我找出问题所在。由于某种原因,这条线导致了泄漏: thumbnailImage = [UIImage imageWithCGImage:[theALSset thumbnail]];知道为什么这不起作用吗?

标签: iphone ios cocoa-touch uiview uiviewcontroller


【解决方案1】:

我将把它放在一个答案而不是大量评论中。

这行(见cmets)会出问题:

thumbnailImage = [UIImage imageWithCGImage:[theALAsset thumbnail]]; 

那是因为thumbnailImage 是一个 ivar。UIImage imageWithCGImage 正在返回一个自动释放的对象。因此,您必须明确保留它,如下所示:

thumbnailImage = [[UIImage imageWithCGImage:[theALAsset thumbnail]] retain]; 

或者,您可以让您的属性通过生成的 setter 为您执行此操作。如下设置属性不会做任何事情,因为在上面的行中,您直接引用thumbnailImage,而不是通过设置器。

@property (nonatomic, retain) UIImage *thumbnailImage;

你需要做的是使用self,所以你有:

self.thumbnailImage = [UIImage imageWithCGImage:[theALAsset thumbnail]]; 

这将通过生成的设置器首先检查任何现有对象,releaseit 如果有,然后对新分配的对象执行retain。这一切都是自动发生的。换句话说,它可以省去你做的麻烦:

-(void)setThumbnailImage:(UIImage *)aThumbnailImage
{
    [aThumbnailImage retain];
    if (thumbnailImage)
    {
        [thumbnailImage release];
    }
    thumbnailImage = aThumbnailImage;
}

Aaron Hillegass 的书在“Mac OS X 的 Cocoa 编程”中对这些内容进行了很好的解释。

要做的关键事情是使用分析器运行构建,或者只是不时运行分析器。在您进入耗时的追踪 EXC_BAD_ACCESS 错误的过程之前,它会发现很多此类问题。

【讨论】:

    【解决方案2】:

    EXC_BAD_ACCESS 表示您提供了一个无效的指针(在这种情况下,nil 可以被认为是“有效的”)。在您的第一种情况下,错误指针似乎是photos

    如果它是一个自动变量,它可能是坏的,因为你没有初始化它,但系统总是将实例变量归零。

    所以要么你给它分配了一些无效的东西,要么它里面的值仍然存在,但是它所寻址的对象已经被释放了。

    第二种情况的错误奇怪地表明“self”已被释放。这很可能是您的根本问题,您的dealloc 方法正在释放photos,因此首先显示错误。我建议您在 dealloc 例程中放置一个 NSLog 以查看它是否被过早调用,如果是,那么显然要弄清楚您是如何未能正确保留控制器对象的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-17
      • 1970-01-01
      • 2016-04-12
      相关资源
      最近更新 更多