NSMutableArray在枚举时发生了变异

时间:2017-01-07 19:43:38

标签: objective-c arrays macos cocoa

我在一个旧的Objective-C应用程序中有一个数组,我用它来学习更多"复杂"编码。它是从OS X的旧时代回来的,并且非常破碎。我已经让它工作(大多数)!但是,该应用程序有一个NSMutableArray图像,总共7个。我使用随机数生成器在屏幕上插入图像,一些代码允许它们下降,然后,使用屏幕边界,当它们到达" 0"在Y轴上,它们将从阵列中移除。 我最初只是:

if( currentFrame.origin.y+currentFrame.size.height <= 0 )
        {
         [flakesArray removeObject:myItem];

我从数组中删除对象时已经读过,最好反过来迭代...所以我有这段代码:

for (NSInteger i = myArray.count - 1; i >= 0; i--)
     { //added for for statement
   if( currentFrame.origin.y+currentFrame.size.height <= 0 )
        {
    [myArray removeObjectAtIndex:i];
        }

可悲的是,这两种方法都会在枚举错误时导致相同的变异。我错过了一些明显的东西吗 如果我添加一个NSLog语句,我认为我可以得到需要删除的项目的索引:

NSLog (@"Shazam! %ld", (long)i);

2017-01-07 14:39:42.086667 MyApp [45995:7500033] Shazam! 2

我已经仔细研究过并尝试了几种不同的方法,包括这个one,它看起来是最受欢迎的同一错误。

提前谢谢!我很乐意提供任何其他信息!

添加更多: 对不起伙计我没有明确地调用NSFastEnumeration,但我有这个:

- (void) drawRectCocoa:(NSRect)rect
{
    NSEnumerator* flakesEnum = [flakesArray objectEnumerator];

然后

for( i = 0; i < numberToCreate; i++ )
    {
        [self newObject:self];
    }
  while( oneFlake = [flakesEnum nextObject] )

在这里:

 if( currentFrame.origin.y+currentFrame.size.height <= 0 )
       {
        NSLog (@"Shazam! %i", oneFlake);
 [flakesArray removeObject:oneFlake];
}

谢谢大家。我从这次讨论中学到了很多东西!

2 个答案:

答案 0 :(得分:3)

有两种方法:(1)收集要删除的对象,然后使用removeObjectsInArray:将其删除。

<html>
<head>

  <link rel=StyleSheet href="/static/style.css" type="text/css" media="screen">

</head>

<body>

<div id="content">
  {{ tweet }}
</div>


</body>
</html>

或者,NSMutableArray *removeThese = [NSMutableArray array]; for (id item in myArray) { if (/* item satisfies some condition for removal */) { [removeThese addObject:item]; } } // the following (and any other method that mutates the array) must be done // *outside of* the loop that enumerates the array [myArray removeObjectsInArray:removeThese]; 可以容忍在迭代期间删除...

reverseObjectEnumeration

答案 1 :(得分:2)

根据错误,当任何foreach (Control control in this.Controls) { if (control is PictureBox) { this.Controls.Remove(control); } } (或任何NSMutableArray集合)被枚举为任何快速枚举循环(NSMutable...)的一部分时,您可能不会改变它。

@ danh的答案也有效,但涉及分配新的元素数组。有两种更简单,更有效的方法来过滤数组:

for (... in ...) { ... }

[array filterUsingPredicate:[NSPredicate predicateWithBlock:^(id element, NSDictionary<NSString *,id> *bindings) {
    // if element should stay, return YES; if it should be removed, return NO
}];

filterUsingPredicate:可能稍快一些(因为它本身使用快速枚举),但根据具体应用,removeObjectsAtIndexes:可能更灵活。

无论如何,如果你在快速枚举循环中使用你的数组,你将不得不在循环之外执行修改。您可以使用NSMutableIndexSet *indicesToRemove = [NSMutableIndexSet new]; for (NSUInteger i = 0; i < array.count; i += 1) { if (/* array[i] should be removed */) { [indicesToRemove addIndex:i]; } } [array removeObjectsAtIndexes:indicesToRemove]; 完全替换循环,也可以保持循环并跟踪要删除的元素的索引以供日后使用。