【问题标题】:Objective-C Object gone due to memory management in NSMutableArray由于 NSMutableArray 中的内存管理,Objective-C 对象消失了
【发布时间】:2012-02-21 09:43:34
【问题描述】:

在向NSMutableArray 添加对象时,我遇到了关于内存管理的问题。奇怪的是,我添加的前 8 个对象一切正常,但添加第 9 个对象时,应用程序在检索此对象时崩溃。

UploadStatus *status = [[UploadStatus alloc] initWithStatus:[NSString stringWithFormat:@"%@: %d", NSLocalizedString(@"uploadPictureSucceeded", @""), pic_id] 
                                                 andImageInProgress:nil 
                                                    imageForSuccess:nil 
                                                     imageForFailed:nil];
[self.delegate notify:status];
[status release];

这是在几个不同文本的地方进行的。但是这个对象包含我在UITableView 中显示的状态。

在委托的 notify 方法中,我将 UploadStatus 对象添加到 NSMutableArray 并重新加载显示该数组中的对象的 UITableView

前 8 次我将 UploadStatus 对象添加到数组并重新加载表,它显示正确。但我第 9 次收到错误 [CFString retain]: message sent to deallocated instance 0x5c655c0。在cellForRowAtIndexPath 方法中重新加载表时会出现此错误。

奇怪的是它总是显示NSMutableArray 中的对象超出了范围,就像下面的截图一样:

尽管如此,如果我获取项目,将其转换为 UploadStatus 类并从中获取 status,一切都会顺利进行(对于前 8 个对象)。

在将第 9 个 UploadStatus 对象添加到 NSMutableArray 后,是否有人知道为什么会出错?

非常感谢您的帮助!

【问题讨论】:

  • 你应该展示你是如何构建 NSMutableArray

标签: objective-c memory nsmutablearray zombie-process


【解决方案1】:

问题在于这段代码:

[NSString stringWithFormat:@"%@: %d", NSLocalizedString(@"uploadPictureSucceeded", @""), pic_id]

您没有保留该字符串,因此它会在下一次运行循环执行时消失。您对前 8 个很幸运。由于某种原因,它们碰巧没有被覆盖,或者可能是其他一些对象保留了它们。但是第 9 个不是,你终于看到了错误的结果。

您需要 UploadStatus 对象来保留该字符串(并稍后释放它)。

【讨论】:

  • 你怎么知道(没有看到代码)initWithStatus 没有保留 NSString?按照标准的 Objective-C 编码约定,它应该这样做。
  • 我不知道,但从发生的事情来看,以及我自己犯这个错误的频率,我是有根据的猜测。你说得对,我不确定。
  • 他实际上是对的。将我的 initStatus:... 更改为包含 status = [_status retain]; 实际上解决了这个问题。
【解决方案2】:

我注意到您在此代码块中直接访问您的 ivars,而不是使用访问器。这几乎可以肯定是您问题的根源(它是 ObjC 中内存管理问题的第一大原因)。切换到访问器,您的大部分内存管理问题都会消失。

您还应该继续运行静态分析器 (Build>Analyze)。它可能会有所启发。问题可能不在上面的代码中;它是你存储某些东西的地方,很可能是在一个 ivar 中。

【讨论】:

  • 直接访问 ivars 以在课堂内阅读是完全合法的。
  • 正如你所说的“阅读”,我假设你同意写作,访问器是绝对关键的。具有不同的读写规则会使审计复杂化并使代码不对称,同时几乎没有好处。人们直接写到 ivars 的危险大大超过了直接从他们那里读取的好处。在某些情况下,直接从 ivars 读取是不安全的(多线程代码是最常见的),这使得改掉直接接触 ivars 的习惯更加有利,即使是阅读也是如此。
  • 不幸的是,Objective-C 在最好的情况下是“非对称的”。您总是在 init 和 dealloc 中使用访问器,except,例如。而且,当然,并不是每个 ivar 都是带有访问器的属性(有时是为了让 ivar 不那么“公开”)。
  • 嗯,写到 ivars 有什么问题?和 ivars 你的意思是一般变量?例如,您应该始终使用self.status = @"pending"; 中的访问器吗?为什么?
  • @HotLicks,您可以(并且应该)生成私有属性。我建议永远不要生成“裸”(非属性)ivar。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多