【问题标题】:fast enumeration for removing item in NSMutableArray crash在 NSMutableArray 崩溃中删除项目的快速枚举
【发布时间】:2012-10-18 08:16:14
【问题描述】:

我有一个奇怪的问题,如果我在 forin 枚举中删除我的项目,它会崩溃,所以像这样:

for (Obstacle *obstacleToTrack in _obstaclesToAnimate) {
    //this if else not so important for happening crash
    if(obstacleToTrack.distance > 0){
        obstacleToTrack.distance -= _playerSpeed * _elapsed;
    }else{
        if (obstacleToTrack.watchOut) {
            obstacleToTrack.watchOut = NO;
        }
        obstacleToTrack.x -= (_playerSpeed + obstacleToTrack.speed) * _elapsed;
    }
    if (obstacleToTrack.x < -obstacleToTrack.width || _gameState == GS_OVER) {
        [self removeChild:obstacleToTrack];
        //this line makes crash happen , if remove this line code work fine
        [_obstaclesToAnimate removeObject:obstacleToTrack];
    }
}

如果我将代码更改为

NSMutableArray *forRemoving = [[NSMutableArray alloc]init];
for (Obstacle *obstacleToTrack in _obstaclesToAnimate) {
    //this if else not so important for happening crash
    if(obstacleToTrack.distance > 0){
        obstacleToTrack.distance -= _playerSpeed * _elapsed;
    }else{
        if (obstacleToTrack.watchOut) {
            obstacleToTrack.watchOut = NO;
        }
        obstacleToTrack.x -= (_playerSpeed + obstacleToTrack.speed) * _elapsed;
    }
    if (obstacleToTrack.x < -obstacleToTrack.width || _gameState == GS_OVER) {
        // code change here
        [self removeChild:obstacleToTrack];
        [forRemoving addObject:obstacleToTrack];
    }
}
for(Obstacle *obstacleToTrack in forRemoving){
    [_obstaclesToAnimate removeObject:obstacleToTrack];
    [forRemoving removeObject:obstacleToTrack];
}
[forRemoving release];

这会很完美,有人能告诉我为什么吗?

【问题讨论】:

  • 使用常识,很容易得出在枚举期间不能编辑对象/数组的结论。不过不太清楚为什么。
  • 如果我不应该在迭代时删除数组,为什么我的第二个“forRemoving”示例forloop不会崩溃?

标签: objective-c nsmutablearray fast-enumeration


【解决方案1】:

答案是,如果您删除一个对象,那么该数组中的其他对象会在数组中移动位置,因为一个项目已被删除。

例如,我们有一个包含 4 个项目的数组,如果我们删除第一个项目(项目 0),则以前位于索引 1 的项目现在位于索引 0,而位于 2 的项目现在位于 1。 因此枚举中断。

您可以通过从倒数到 0 循环遍历数组来解决此问题:

for (int i = [array count]-1; i >= 0; i--) {
    id object = [array objectAtIndex:i];

    if (some check) {
       [array removeObjectAtIndex:i];
    }
}

【讨论】:

  • [array count] 返回数组中的项目数,但是可以传递给[array objectAtIndex:] 的最大索引是[array count]-1,所以这在第一次传递时会崩溃。正确的代码是:for (int i = [array count]-1; i &gt;= 0; i--) { ...
  • @rckoenes 你是天才我的朋友? 随机寻找解决方案并找到你的答案。我怎么能忘记这个基本规则!!!
【解决方案2】:

就像 rckoenes 所说,您通过在遍历数组时删除数组中的内容来破坏枚举。

您可以做的是有一个第二个数组,您可以在其中插入要删除的对象。然后,在您的枚举完成后,您可以从第一个数组中删除在第二个数组中找到的所有对象。

【讨论】:

    【解决方案3】:

    您不得在迭代其项目时​​修改集合。

    如果你基于索引进行迭代(即经典的 for 循环),你可以删除一些东西,但要小心调整你的索引。

    【讨论】:

      【解决方案4】:

      查看此链接

      https://developer.apple.com/library/mac/documentation/cocoa/conceptual/Collections/Articles/Enumerators.html

      枚举是“安全的”——枚举器有一个突变保护,这样如果 您尝试在枚举期间修改集合,例外 被提升了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-10
        • 1970-01-01
        • 1970-01-01
        • 2016-03-30
        • 1970-01-01
        • 1970-01-01
        • 2011-09-02
        • 1970-01-01
        相关资源
        最近更新 更多