iPhone-集合< __ NSArrayM:0x1416eea0>在被列举时被突变

时间:2012-08-27 05:47:05

标签: iphone objective-c ios5 nsmutablearray collision

在我的iphone游戏中,当在ios 4.0模拟器上运行时一切正常。但是,当使用5.0模拟器或5.0+设备运行时,应用程序在第一级崩溃,留下错误:

  

由于未捕获的异常'NSGenericException'而终止应用程序,原因:
  ***集合< __ NSArrayM:0x1416eea0>在被列举的同时发生了变异   ***首先抛出调用堆栈:
  (0x1d6a052 0x20d0d0a 0x1d69c21 0x6f8e 0x8bd48 0x94020 0xba169 0xbcee4 0x85a2db 0x85a1af 0x1d3e966 0x1d3e407 0x1ca17c0 0x1ca0db4 0x1ca0ccb 0x2702879 0x270293e 0x90fa9b 0x1f31 0x1eb5 0x1)
  终止调用抛出异常(lldb)

我认为我已经将问题缩小到这段代码。我知道问题是在for-loop中移除对象但似乎无法找到解决方案。

这是我的代码:

//remove the projectile

for (CCSprite *projectile in projectilesToDelete) {
    [_projectiles removeObject:projectile];
    [self removeChild:projectile cleanup:YES];
}       
[projectilesToDelete release];

//remove the projectile

for (CCSprite *targetDel in targetsToDelete) {  
    targetDel.position = ccp(-2000, -2000);
    [self removeChild:targetDel cleanup:YES];
    [_targets removeObject:targetDel];
}                        
[targetsToDelete release];

请帮忙,过去几天一直想弄清楚。

2 个答案:

答案 0 :(得分:2)

简而言之,表达式:

for (OBJ * VAR in COLLECTION) {

使用名为快速枚举的技术。这里发生的是编译器在堆栈上插入一些隐藏的后备存储,并从可枚举的类型中请求一组元素。因为它一次抓取许多对象并对它们进行迭代,所以在枚举容器(COLLECTION)时变错是错误的,因为堆栈区域和集合可能不同步。

解决方法是在您改变枚举内容时避免快速枚举 - 或者在某些情况下可以枚举副本。标准for(i;c;e)循环不使用快速迭代 - 但for(in)确实使用它。


改变程序以避免快速枚举错误的一种方法是:

// remove the projectile
while (projectilesToDelete.count) {
    CCSprite * projectile = projectilesToDelete[0];
    [_projectiles removeObject:projectile];
    [self removeChild:projectile cleanup:YES];
}
[projectilesToDelete release];

// remove the projectile
while (targetsToDelete.count) {
    CCSprite * targetDel = targetsToDelete[0];
    targetDel.position = ccp(-2000, -2000);
    [self removeChild:targetDel cleanup:YES];
    [_targets removeObject:targetDel];
}
[targetsToDelete release];

答案 1 :(得分:1)

你的代码有问题,考虑到这个...... projectilesToDelete数组有3个元素(A,B,C)......

在第一次迭代中,删除对象(A)..在该数组计数变为2,即,数组内容将是(B,C)但它认为它是3(B,C,Nil)。

所以在枚举时修改了数组。所以它会给出一个例外。

将代码更改为此

// get array length
int count = projectilesToDelete. length;

// iterate through the array    
for (int iter = 0; iter < count; inter++) 
{
     CCSprite *projectile = projectilesToDelete [iter];

     [_projectiles removeObject:projectile];

     [self removeChild:projectile cleanup:YES];

      // decrement count
      count--;
      iter--;
}