【问题标题】:Keep a class-level array of instantiated objects without having to explicitly remove them保留实例化对象的类级别数组,而无需显式删除它们
【发布时间】:2014-02-24 23:54:18
【问题描述】:

我有一个类,比如说Chicken,我想要一个类级别的方法来枚举所有当前存在的Chickens。为此,我保留了一个类级别的NSMutableArray 并在init 方法中将self 添加到此。

这很好,我的枚举方法只是返回一个指向这个数组的(非可变的)指针。

问题是我不能再通过删除所有指向它的指针来释放鸡,因为数组中总是有一个强指针。

例如如果我这样做......

Chicken *chick = [[Chicken alloc] init];
// Do something with the chick
chick = nil;

鸡之所以存在,是因为数组中有一个指向它的强指针。我可以有一个-[Chicken kill] 方法,将它从数组中删除,但这并不整洁。

解决这个问题最好的方法是什么?

【问题讨论】:

  • 在数组中使用弱引用。 NSValue 支持非保留对象,但如果你想要一个自动归零引用,你可以使用这篇文章的后半部分:stackoverflow.com/questions/4224495/…
  • 一旦考虑到多线程,这是一个很难维护的设计。小心。

标签: objective-c cocoa memory-management


【解决方案1】:

您可以使用[NSHashTable weakObjectsHashTable] 来存储对象。它基本上是一个包含弱引用的数组。它既安全又干净。

如果NSHashTable 不可用或合适(您想保存像NSDictionary 这样的键值对)但您有支持__weak 的ARC,则可以使用包装器对象来保存弱引用。

在这个例子中我使用块来保存弱引用

NSMutableDictionary *globalDict = [NSMutableDictionary dictionary];

// put object
id obj = [Foo new];
__weak id weakRef = obj;
globalDict[key] = [^() { return weakRef; } copy];

// read object
id (^block)(void) = globalDict[key];
id obj = block ? block() : nil;
if (!obj) {
    [globalDict removeObjectForKey:key];
}

【讨论】:

  • 另一个不错的选择。像往常一样,应该小心线程安全和非保留指针。
  • 因为我只对拥有一袋鸡感兴趣并且不担心顺序,如果我正确理解 +weakObjectsHashTable 将创建一个表以杀死一个表,那么 NSHashTable 看起来最简单鸡会把它从桌子上移开吗?
  • @Thickycat 是的,这就是你想要的。
【解决方案2】:

在数组中使用 + (NSValue *)valueWithNonretainedObject:(id)anObject 值。为了简化您的 API,您可以创建 +arrayOfAllChickens 的包装方法,该方法将迭代所有未保留的值并将它们添加到数组中并返回。

请记住从dealloc 中的数组中删除值,否则您可能会遇到错误的访问崩溃。

【讨论】:

  • 这是正确的方法,请注意,这不会自动归零引用,这意味着如果您尝试向死鸡发送消息,您可能会遇到 EXC_BAD_ACCESS 问题。
  • @RichardJ.RossIII 刚刚为此添加了评论。 :-) “死鸡”很不错!
  • 谢谢 Leo,我想将两个答案都标记为正确,但似乎不可能,所以我选择了 NSHashTable,因为我正在使用它,尽管你的“与另一个类间接”方法是这样的当我考虑如何饲养我的鸡时,它在我脑海中浮现。嗯,我可以将 NSHashTable* 称为“政变”...
  • @Thickycat 当然,现在担心。这是更好的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-08
  • 2021-11-23
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多