避免"NSArray在被枚举时发生变异"

gle*_*rey 43 collections cocoa cocoa-touch objective-c nsmutablearray

我有一个NSMutableArray存储用于Box2d物理模拟的鼠标接口.当使用多个手指播放时,我会得到例外陈述

NSArray在被枚举时发生了变异

我知道这是因为我正在从数组中删除对象,同时也通过它枚举,使枚举无效.

我想知道的是,解决这个问题的最佳策略是什么?我在网上看到了一些解决方案:@synchronized在枚举或将触摸关节放入垃圾数组之前复制数组以便以后删除(我不确定是否可行,因为我需要在移除后直接从数组中删除鼠标点它来自世界).

dan*_*ndi 47

您始终可以在没有枚举器的情况下进行迭代.这意味着一个常规的for循环,当你删除一个对象时: - 递减索引变量并继续; .如果在进入for循环之前缓存数组的计数,那么确保在删除对象时也减少该数量.

无论如何,我不明白为什么带有对象以便以后删除的数组会出问题.我不知道你所拥有的确切情况和涉及的技术,但理论上应该没有问题.因为在大多数情况下使用此方法时,您只能在第一次枚举中执行任何操作,并在枚举删除数组时执行实际操作.如果您遇到的情况是,在第一个枚举中您再次针对同一个数组检查某些内容,并且您需要知道对象不再存在,您可以添加一个检查以查看它们是否在删除数组中.

无论如何,希望我帮助.祝好运!

  • "无论如何,希望我帮助过"; 当然帮助了我,很多!谢谢! (2认同)

edc*_*591 37

你可以这样做:

NSArray *tempArray = [yourArray copy];
for(id obj in tempArray) {
    //It's safe to remove objects from yourArray here.
}
[tempArray release];
Run Code Online (Sandbox Code Playgroud)

  • 这不是真的.在枚举异常时我仍然会发生变异. (26认同)
  • @TimArnold我很确定会得到相同的结果. (2认同)

mar*_*ker 33

最简单的方法是向后枚举数组,这意味着删除对象时下一个索引不会受到影响.

for (NSObject *object in [mutableArray reverseObjectEnumerator]) {
    // it is safe to test and remove the current object      
    if (AddTestHere) {
        [savedRecentFiles removeObject: object];
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 简单而聪明. (4认同)

DaN*_*aNY 5

锁定(@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
}
Run Code Online (Sandbox Code Playgroud)

它每次复制n + 1个对象.你可以在这里使用lock,但如果有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
}
Run Code Online (Sandbox Code Playgroud)