0

好吧,我已经从事编码工作 12 年了,但我对 Obj-C 的经验相对缺乏——尤其是内存管理——而且我遇到了一个令我惊讶的错误。

这是代码块:

    // self.contained is an NSMutableSet
    NSEnumerator *e = [self.contained objectEnumerator];
>>  while (CCNode *node = [e nextObject]) {
        if (!node.body || ![self validate:node]) {
            [self.contained removeObject:node];
        }
    }

_NSZombie_NSException>>. 好的,我知道这意味着(总是?)我正在访问一个已dealloc编辑的对象。我不明白为什么这条线上会发生错误。如果node我得到的是已dealloc编辑的内容,我希望下一行出现错误(例如,当我访问时node.body)。我看不出NSEnumerator对象本身是如何导致问题的,因为它是在之前创建的,如果它是self.contained集合,它应该在之前就死了,对吧?

那么,nextObject实际上是否在检索到的对象(即)上调用了一些node会导致抛出异常的方法?这也许可以解释它,但我没想到会是这样。或者谁能​​告诉我哪个物体可能是僵尸?

这种情况非常间歇性地发生,我在开发的最后一周左右遇到过两次,因此运行僵尸仪器不太可能捕获它。

4

2 回答 2

1

来自“集合编程主题”中的“使用枚举器”:

在枚举可变集合时删除、替换或添加到可变集合的元素是不安全的。如果您需要在枚举期间修改集合,您可以制作该集合的副本并使用该副本进行枚举,或者在枚举期间收集您需要的信息并在之后应用更改。

[self.contained removeObject:node];

您在枚举时从集合中删除一个对象。

于 2013-09-02T08:42:27.403 回答
0

枚举时不要从任何集合中添加或删除对象。

创建一个副本并枚举该副本并操作原始副本。完成后处理副本。

假设你 ARC 一个小的改变就可以了。

  for (CCNode *node in [self.contained allObjects]) {  // for contained being an NSSet
        if (!node.body || ![self validate:node]) {
            [self.contained removeObject:node];
        }
    }

  for (CCNode *node in [NSArray arrayWithArray:self.contained]) {  // for contained being an NSArray
        if (!node.body || ![self validate:node]) {
            [self.contained removeObject:node];
        }
    }

  for (CCNode *node in [NSDictionary dictionaryWithDictionary:self.contained]) {  // for contained being an NSDictionary. However, allObjects or allKeys may suit you well too depending on what you need.
        if (!node.body || ![self validate:node]) {
            [self.contained removeObject:node];
        }
    }

如果您不使用 ARC,则在新创建的未命名集合对象上添加对 autorelease 方法的调用。喜欢 for (CCNode *node in [[self.contained allObjects] autorelease])

如果您更喜欢显式枚举器,请执行以下操作:

NSEnumerator *e = [[self.contained allObjects] objectEnumerator];
while (CCNode *node = [e nextObject]) {
于 2013-09-02T08:42:43.563 回答