避免“NSArray被列举时发生了变异”
我有一个NSMutableArray
为Box2d物理模拟存储mousejoints。 当使用多个手指玩我会得到例外说明
枚举时,NSArray发生了变异
我知道这是因为我从数组中删除对象,同时枚举通过它,使枚举无效。
我想知道什么是最好的战略来解决这个未来? 我已经看到了一些在线解决scheme: @synchronized
,枚举之前复制数组或将触摸接点放入一个垃圾数组以供以后删除(我不知道会工作,因为我需要从列直接删除鼠标连接从世界中删除后)。
你总是可以迭代而不用枚举器。 这意味着一个规则的循环,当你删除一个对象: – 减less索引variables,并继续; 。 如果你在进入for循环之前caching数组的数量,那么当删除一个对象的时候,确保你也减less了数组的数量。
无论如何,我不明白为什么一个数组与对象以后去除将是一个问题。 我不知道你所拥有的确切情况和所涉及的技术,但理论上应该不存在问题。 因为在大多数情况下,当使用这个方法时,你可以在第一个枚举中不做任何事情,并且在枚举移除数组的时候做真正的工作。 如果你有一个情况,在第一个枚举中,你再次检查对象的数组,你需要知道对象不在那里,你可以添加一个检查,看看他们是否在删除数组。
无论如何,希望我帮助。 祝你好运!
你可以做这样的事情:
NSArray *tempArray = [yourArray copy]; for(id obj in tempArray) { //It's safe to remove objects from yourArray here. } [tempArray release];
最简单的方法是向后枚举数组,这意味着在删除对象时下一个索引不会受到影响。
for (NSObject *object in [mutableArray reverseObjectEnumerator]) { // it is safe to test and remove the current object if (AddTestHere) { [savedRecentFiles removeObject: object]; } }
锁(@synchronized)操作要快得多,一遍又一遍地复制整个数组。 当然,这取决于数组有多less元素,以及执行的频率。 想象一下你有10个线程同时执行这个方法:
- (void)Callback { [m_mutableArray addObject:[NSNumber numberWithInt:3]]; //m_mutableArray is instance of NSMutableArray declared somewhere else NSArray* tmpArray = [m_mutableArray copy]; NSInteger sum = 0; for (NSNumber* num in tmpArray) sum += [num intValue]; //Do whatever with sum }
它每次都复制n + 1个对象。 你可以在这里使用locking,但是如果有100k个元素要迭代呢? 数组将被locking,直到迭代完成,其他线程将不得不等待,直到释放锁。 我认为在这里复制对象更有效,但是这也取决于对象的大小,以及你在迭代中做什么。 锁应该始终保持最短的时间。 所以我会使用锁来做这样的事情。
- (void)Callback { NSInteger sum = 0; @synchronized(self) { if(m_mutableArray.count == 5) [m_mutableArray removeObjectAtIndex:4]; [m_mutableArray insertObject:[NSNumber numberWithInt:3] atIndex:0]; for (NSNumber* num in tmpArray) sum += [num intValue]; } //Do whatever with sum }
使用for循环而不是枚举是可以的。 但是,一旦你开始删除数组元素,要小心,如果你使用线程。 仅仅减less柜台是不够的,因为你可能会删除错误的东西。 正确的方法之一是创build数组的副本,迭代复制和从原始删除。
edc1591是正确的方法。
[Brendt:在迭代时需要从原始文件中删除]
for(MyObject *obj in objQueue) { //[objQueue removeObject:someof];//NEVER removeObject in a for-in loop [self dosomeopearitions]; } //instead of remove outside of the loop [objQueue removeAllObjects];
我有同样的问题,解决scheme是枚举副本并改变原来的正确提到edc1591。 我已经尝试了代码,我没有得到错误了。 如果你仍然得到错误,这意味着你仍然在for循环中改变副本(而不是原来的)。
NSArray *copyArray = [[NSArray alloc] initWithArray:originalArray]; for (id obj in copyArray) { // tweak obj as you will [originalArray setObject:obj forKey:@"kWhateverKey"]; }
以上所有都不适合我,但是这样做:
while ([myArray count] > 0) { [<your delete method call>:[myArray objectAtIndex:0]]; }
注意:这将全部删除。 如果您需要select哪些项目需要删除,那么这将无法正常工作。
也许你在枚举它时删除或添加了对象到你的mutableAray。 在这种情况下,我的情况出现错误。
我遇到了这个错误,在我的情况下,这是因为multithreading的情况。 一个线程正在枚举一个数组,而另一个线程同时从同一个数组中移除了对象。 希望这有助于某人。