NSEnumerator :: nextObject上的NSZombie异常(或者,nextObject会触摸它的查询吗?)

时间:2013-09-02 08:34:34

标签: objective-c nszombie nsenumerator

好吧,我已经按照交易编码了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 ed的对象。我没有得到的是为什么错误发生在这一行。如果node我得到的是dealloc,那么我希望下一行出错(例如,当我访问node.body时)。我无法看到NSEnumerator对象本身是如何导致问题的,因为它是在之前创建的,如果它是self.contained集,它应该在之前的行上死掉>,对吧?

那么,nextObject是否实际上在检索到的对象上调用了一些方法(即node),这会导致抛出异常?这也许可以解释它,但我不会想到会出现这种情况。或者任何人都可以告诉我哪个对象可能是僵尸?

这种情况发生在非常间歇性地发生,我在上周左右开发了两次,所以运行僵尸乐器不太可能陷入困境。

2 个答案:

答案 0 :(得分:1)

来自"Using an Enumerator""收藏集编程主题":

  

删除,替换或添加可变集合是不安全的   通过它枚举的元素。如果你需要修改一个   在枚举期间收集,你可以复制一份   使用副本收集和枚举或收集您的信息   在枚举期间要求并在之后应用更改。

[self.contained removeObject:node];

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

答案 1 :(得分:0)

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

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

假设你有一个小小的改变就行了。

  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]) {