我有一个NSMutableArray
存储用于 Box2d 物理模拟的鼠标关节。当使用超过一根手指弹奏时,我会得到例外说明
NSArray 在枚举时发生了变异
我知道这是因为我正在从数组中删除对象,同时还枚举它,使枚举无效。
我想知道的是解决这个问题的最佳策略是什么?我在网上看到了一些解决方案:@synchronized
,在枚举之前复制数组或将触摸关节放入垃圾数组以供以后删除(我不确定这是否可行,因为我需要在删除后立即从数组中删除鼠标关节它来自世界)。
我有一个NSMutableArray
存储用于 Box2d 物理模拟的鼠标关节。当使用超过一根手指弹奏时,我会得到例外说明
NSArray 在枚举时发生了变异
我知道这是因为我正在从数组中删除对象,同时还枚举它,使枚举无效。
我想知道的是解决这个问题的最佳策略是什么?我在网上看到了一些解决方案:@synchronized
,在枚举之前复制数组或将触摸关节放入垃圾数组以供以后删除(我不确定这是否可行,因为我需要在删除后立即从数组中删除鼠标关节它来自世界)。
您始终可以在没有枚举器的情况下进行迭代。这意味着一个常规的 for循环,当你删除一个对象时: - 减少索引变量并继续;. 如果您在进入 for 循环之前缓存数组的计数,那么请确保在删除对象时也减少该计数。
无论如何,我不明白为什么带有稍后删除对象的数组会成为问题。我不知道您的确切情况和所涉及的技术,但理论上应该没有问题。因为在大多数情况下,使用此方法时,您可以在第一次枚举中什么都不做,而在枚举删除数组时做真正的工作。如果您在第一次枚举中再次针对同一个数组检查某些内容,并且您需要知道这些对象不再存在,您只需添加一个检查以查看它们是否在删除数组中。
无论如何,希望我有所帮助。祝你好运!
你可以这样做:
NSArray *tempArray = [yourArray copy];
for(id obj in tempArray) {
//It's safe to remove objects from yourArray here.
}
[tempArray release];
最简单的方法是通过数组向后枚举,这意味着删除对象时不会影响下一个索引。
for (NSObject *object in [myMutableArray reverseObjectEnumerator]) {
// it is safe to test and remove the current object
if (AddTestHere) {
[myMutableArray removeObject: object];
}
}
锁定(@synchronized)操作比一遍又一遍地复制整个数组要快得多。当然,这取决于数组有多少元素,以及它执行的频率。假设您有 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 个对象。你可以在这里使用锁,但是如果有 100k 个元素需要迭代呢?数组将被锁定直到迭代完成,其他线程将不得不等待直到锁定被释放。我认为在这里复制对象更有效,但这也取决于该对象有多大以及您在迭代中做了什么。锁应始终保持最短时间。所以我会用锁来做这样的事情。
- (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
}
以上所有对我都不起作用,但这确实:
while ([myArray count] > 0)
{
[<your delete method call>:[myArray objectAtIndex:0]];
}
注意:这将全部删除。如果您需要选择需要删除的项目,那么这将不起作用。
使用 for 循环而不是枚举是可以的。但是一旦你开始删除数组元素,在使用线程时要小心。仅仅减少计数器是不够的,因为您可能正在删除错误的东西。正确的方法之一是创建数组的副本,迭代副本并从原始副本中删除。
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];
我遇到了同样的问题,解决方案是枚举副本并改变原件,正如 edc1591 正确提到的那样。我已经尝试了代码,但我不再收到错误消息。如果您仍然收到错误,则意味着您仍在 for 循环内更改副本(而不是原始副本)。
NSArray *copyArray = [[NSArray alloc] initWithArray:originalArray];
for (id obj in copyArray) {
// tweak obj as you will
[originalArray setObject:obj forKey:@"kWhateverKey"];
}
也许您在枚举 mutableAray 时删除或添加了对象。在我的情况下,这种情况下出现了错误。
我遇到了这个错误,就我而言,这是因为多线程情况。一个线程正在枚举一个数组,而另一个线程同时从同一个数组中删除了对象。希望这可以帮助某人。