在 Objective C (ARC) 中避免树状数据结构中的保留循环
Avoiding retain cycles in tree-like data structure in Objective C (ARC)
我在 Objective C 中有一个带有保留周期的数据结构,我正试图找到一种合理的方法来打破它们。由于我对数据结构的要求,None 的常用规则似乎在这里有所帮助(例如 "use weak for parent relationships")。
数据结构本质上是一棵树。但是,我想确保,如果保留树中的 any 个节点,则保留整个树。例如,在这个非常简单的树中:
A
/ \
B C
如果有人保留了 A、B 或 C,那么整棵树都应该保留,并且可以从任何节点 up/down 遍历。只有当没有人保留 any 个节点时,才应释放树中的节点。
我想出的仅有的两个解决方案都不是很漂亮。有谁知道更优雅的解决方案?
作为参考,这是我想到的两个解决方案(两者都与 retainCount 混淆,这很糟糕):
创建一个 TreeHelper 对象,它牢固地保存在树中的所有节点上。所有节点都使用弱指针来引用所有其他节点。当它们的 retainCount > 1 时,树中的所有节点都强烈地持有 TreeHelper,而当 retainCount == 1 时,则弱地持有 TreeHelper。这应该有效,但要求我们使用非 ARC 代码,以便我们可以覆盖 retain/release 并更改 TreeHelper 的所有权.
创建一个 TreeHelper 对象,该对象强烈保留树中的所有对象。所有节点都使用弱指针来引用所有其他节点并强持有 TreeHelper。它会定期执行垃圾回收并检查所有对象的 retainCount。如果它们都是 == 1,那么它会清除所有对象以释放它们。这应该也可以,但是垃圾回收不是很好并且有一些严重的线程安全问题。
没有什么可以阻止您将 ARC 用于您的 "treehelper" 方案。
首先,让你的树不透明。对节点的任何访问(对它们的父节点有弱引用以避免保留循环)都会通过 treehelper 的方法(可以将其称为 TreeWrapper 或 TreeRef)。
每当任何第三方访问一个节点时,你return一个新的数据结构NodeWrapper
,它对你想要的特定节点和根节点都有很强的引用。第三方建立了对该对象的强引用,而不是节点本身。
结果是,当这些对象中的最后一个被释放时,整个树也被释放,只要有一个 NodeWrapper
存在,你的树就存在,满足你的要求。
Never use retainCount
for anything, even if you aren't using ARC.
我在 Objective C 中有一个带有保留周期的数据结构,我正试图找到一种合理的方法来打破它们。由于我对数据结构的要求,None 的常用规则似乎在这里有所帮助(例如 "use weak for parent relationships")。
数据结构本质上是一棵树。但是,我想确保,如果保留树中的 any 个节点,则保留整个树。例如,在这个非常简单的树中:
A
/ \
B C
如果有人保留了 A、B 或 C,那么整棵树都应该保留,并且可以从任何节点 up/down 遍历。只有当没有人保留 any 个节点时,才应释放树中的节点。
我想出的仅有的两个解决方案都不是很漂亮。有谁知道更优雅的解决方案?
作为参考,这是我想到的两个解决方案(两者都与 retainCount 混淆,这很糟糕):
创建一个 TreeHelper 对象,它牢固地保存在树中的所有节点上。所有节点都使用弱指针来引用所有其他节点。当它们的 retainCount > 1 时,树中的所有节点都强烈地持有 TreeHelper,而当 retainCount == 1 时,则弱地持有 TreeHelper。这应该有效,但要求我们使用非 ARC 代码,以便我们可以覆盖 retain/release 并更改 TreeHelper 的所有权.
创建一个 TreeHelper 对象,该对象强烈保留树中的所有对象。所有节点都使用弱指针来引用所有其他节点并强持有 TreeHelper。它会定期执行垃圾回收并检查所有对象的 retainCount。如果它们都是 == 1,那么它会清除所有对象以释放它们。这应该也可以,但是垃圾回收不是很好并且有一些严重的线程安全问题。
没有什么可以阻止您将 ARC 用于您的 "treehelper" 方案。
首先,让你的树不透明。对节点的任何访问(对它们的父节点有弱引用以避免保留循环)都会通过 treehelper 的方法(可以将其称为 TreeWrapper 或 TreeRef)。
每当任何第三方访问一个节点时,你return一个新的数据结构NodeWrapper
,它对你想要的特定节点和根节点都有很强的引用。第三方建立了对该对象的强引用,而不是节点本身。
结果是,当这些对象中的最后一个被释放时,整个树也被释放,只要有一个 NodeWrapper
存在,你的树就存在,满足你的要求。
Never use retainCount
for anything, even if you aren't using ARC.