3

奇妙な問題があります。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];

これは完璧に機能します。誰かが理由を教えてもらえますか?

4

4 に答える 4

6

答えは、オブジェクトを削除すると、アイテムが削除されるため、その配列内の他のオブジェクトが配列内の位置を移動するということです。

たとえば、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];
    }
}
于 2012-10-18T08:20:51.873 に答える
3

rckoenesが言ったように、配列を反復しながら配列内のものを削除することにより、列挙を壊します。

できることは、削除するオブジェクトを挿入する 2 番目の配列を用意することです。次に、列挙が終了したら、2 番目の配列で見つかったすべてのオブジェクトを最初の配列から削除できます。

于 2012-10-18T08:28:31.623 に答える
1

このリンクを確認してください

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

列挙は「安全」です。列挙子にはミューテーションガードがあるため、列挙中にコレクションを変更しようとすると、例外が発生します。

于 2012-10-18T09:03:38.380 に答える
1

コレクションの項目を繰り返し処理している間は、コレクションを変更してはなりません。

インデックス ベース (つまり、従来の for ループ) を反復する場合、要素を削除できますが、インデックスの調整には注意してください。

于 2012-10-18T08:22:48.797 に答える