好吧,我已经按照交易编码了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
),这会导致抛出异常?这也许可以解释它,但我不会想到会出现这种情况。或者任何人都可以告诉我哪个对象可能是僵尸?
这种情况发生在非常间歇性地发生,我在上周左右开发了两次,所以运行僵尸乐器不太可能陷入困境。
答案 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]) {