【问题标题】:Avoiding retain cycles in tree-like data structure in Objective C (ARC)在 Objective C (ARC) 中避免树状数据结构中的保留循环
【发布时间】:2015-08-12 15:50:45
【问题描述】:

我在 Objective C 中有一个带有保留周期的数据结构,我正试图找出一种合理的方法来打破它们。由于我对数据结构的要求,这里的常用规则似乎都没有帮助(例如“对父关系使用弱”)。

数据结构本质上是一棵树。但是,我想确保,如果保留树中的 any 节点,则保留整个树。例如,在这个非常简单的树中:

  A
 / \
B   C

如果有人保留了 A、B 或 C,那么应该保留整个树并且可以从任何节点向上/向下移动。只有在没有人保留任何个节点时,才应释放树中的节点。

我想出的仅有的两个解决方案不是很漂亮。有谁知道更优雅的解决方案?

作为参考,以下是我想到的两个解决方案(两者都与retainCount混淆,这很恶心):

  1. 创建一个 TreeHelper 对象,该对象强烈地保存在树中的所有节点上。所有节点都使用弱指针来引用所有其他节点。树中的所有节点在其 retainCount > 1 时强烈保留 TreeHelper,而在 retainCount == 1 时弱保留。这应该有效,但需要我们使用非 ARC 代码,以便我们可以覆盖保留/释放并更改 TreeHelper 的所有权。

  2. 创建一个 TreeHelper 对象,该对象强烈地持有树中的所有对象。所有节点都使用弱指针来引用所有其他节点并强持有 TreeHelper。它会定期执行垃圾回收并检查所有对象的retainCount。如果它们都是 == 1,那么它会清除所有对象以释放它们。这也应该可以,但是垃圾收集并不漂亮,并且存在一些严重的线程安全问题。

【问题讨论】:

  • 不要使用retainCount,为类添加计数。系统retainCount 由系统根据系统需要进行管理/更改。此外,通过不使用retainCount,您可以使用 ARC。
  • @zaph 说了什么。我不得不调试在某些retainCount 值上切换行为的代码。这是精神错乱的诱导;一个流浪者retain/autorelease,突然之间,您的缓存语义更改代码在池排水的中间启动,而不是在有序的对象图破坏中间。

标签: objective-c tree automatic-ref-counting


【解决方案1】:

没有什么可以阻止您将 ARC 用于您的“treehelper”方案。

首先,让你的树不透明。对节点的任何访问(对它们的父节点有弱引用以避免保留循环)都通过 treehelper 的方法(可能将其称为 TreeWrapper 或 TreeRef)。

每当任何第三方访问一个节点时,您都​​会返回一个新的数据结构NodeWrapper,它对您想要的特定节点和根节点都有强引用。第三方建立对此对象的强引用,而不是节点本身。

结果是,当这些对象中的最后一个被释放时,整个树也被释放,只要有一个NodeWrapper 存在,您的树就会存在,满足您的要求。

Never use retainCount for anything, even if you aren't using ARC.

【讨论】:

  • 谢谢!好主意;这应该可以工作,即使它需要我重构我的大部分 API 以返回包装器......:/
  • Sorry :(... 您可以通过让包装器将自己呈现为节点的子类来缓解这些问题,但实际上只是将所有相关消息转发到“真实”节点,因为客户端实际上不应该知道或关心对整个树的强引用,或者您可以使用NSProxy
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-16
  • 2014-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多