NSEnumerator::nextObject上的NSZombie异常(或者,nextObject是否接触其查询?)



好吧,我已经用贸易编码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编辑的对象。我不知道为什么这一行会发生错误。如果我得到的nodedealloc,我预计下一行会出现错误(例如,当我访问node.body时)。我看不出NSEnumerator对象本身是如何导致问题的,因为它是在之前创建的,如果它是self.contained集,它应该在之前的行上死亡,对吧?

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

这种情况非常间歇性地发生,在开发的最后一周左右,我已经遇到过两次了,所以运行僵尸工具不太可能捕获它。

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

移除、替换或添加到可变集合的元素。如果需要修改集合,则可以复制使用副本收集和枚举或收集您的信息在枚举期间需要,然后应用更改。

[self.contained removeObject:node];

您可以在枚举对象时将其从集合中删除。

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

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

假设你是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([[self.contained allObjects]autorelease]中的CCNode*节点)

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

NSEnumerator *e = [[self.contained allObjects] objectEnumerator];
while (CCNode *node = [e nextObject]) {

最新更新