UITableView - moveRowAtIndexPath导致内存泄漏

时间:2012-03-11 15:53:39

标签: memory-leaks automatic-ref-counting nsindexpath uitableview

概述

  • 在iOS项目中,我有一个UITableView,我试图移动一行UITableView。
  • 在我的模型中,数据的顺序已经改变,所以我试图在表格中直观地显示它,这就是为什么我使用了UITableView的方法moveRowAtIndexPath:toIndexPath:
  • 为了做到这一点,我创建了一个NSIndexPath实例,我将其传递给UITableView的方法。

泄密时

  • 使用方法indexPathForRow: section:创建NSIndexPath实例时(如代码部分所示),然后将其传递给UITableView的方法moveRowAtIndexPath: toIndexPath:,它会泄漏。

注意:

  • 我正在使用ARC(自动引用计数)
  • XCode 4.3.1
  • 我使用了仪器(Xcode菜单 - 产品>配置文件)来确定内存泄漏

代码:(在UITableViewController内)

NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:newRow inSection:0]; //leaking

[self.tableView beginUpdates];
[self.tableView moveRowAtIndexPath:originalIndexPath toIndexPath:newIndexPath]; //I think this causes the leak
[self.tableView endUpdates];

我尝试过的步骤

  • 注释掉对方法moveRowAtIndexPath:originalIndexPath toIndexPath:的调用,可以防止内存泄漏
  • 我手动使用CFRelease(不确定这是自动参考计数环境中的一个好习惯)

    CFRelease((__ bridge void *)toIndexPath);

问题:

  • 为什么会这样?它有什么解决方案吗?
  • 仪器的内存泄漏结果是否准确?
  • UITableView的方法moveRowAtIndexPath:originalIndexPath toIndexPath:中是否有错误?
  • CFRelease是一个选项吗?有没有一种安全的方法可以防止应用程序崩溃,以防CFRelease尝试释放已经发布的内存(参见上面的确切代码)。

2 个答案:

答案 0 :(得分:1)

您发布的代码不应导致ARC设置中的内存泄漏(在没有ARC的情况下也不应该这样做)。

如果您确实怀疑某个错误(例如UITableView无法释放NSIndexPath对象),您可能会尝试手动将其作为临时解决方法发布。但是,您确定它是在动画完成后才释放它吗?即使你没有动画,也可能是在访问空闲循环之前不会释放indexPath对象(这在GUI组件中非常常见,显然也与自动释放的对象一样)。

然而,为了确认它确实是泄漏,尝试调查内存是否随着时间的推移而增加(可能是UITableView坚持其最新的indexPath对象,其中它可能不会一个问题)。此外,尝试使用NSZombieEnabled环境变量集运行调试器。当您尝试双重释放对象时,这将检测并进入调试器。

答案 1 :(得分:1)

我没有足够的代表添加评论,所以我必须添加答案。我也看到了这个漏洞。我没有使用ARC,我没有使用beginUpdates / endUpdates将单个调用包装到moveRowAtIndexPath:toIndexPath:每当我调用此方法时,Instruments声称NSIndexPath有32个字节的泄漏。

对NSIndexPath的indexPathForRow的调用:inSection:应该返回一个不需要手动释放的自动释放对象。我怀疑moveRowAtIndexPath:toIndexPath:错误地保留了对象,导致泄漏。

我添加了一些调试代码,用于在调用moveRowAtIndexPath:toIndexPath之前和之后记录NSIndexPath的retainCount:并且之前得到1(它在自动释放池上,这是预期的)和之后的5(除非它,否则绝对没有预期)已被添加到自动发布池4次!)

编辑:另请参阅https://devforums.apple.com/message/639904(需要Apple Developer帐户)