2012年9月30日日曜日

高速列挙でエラー「Collection was mutated while being enumerated.」が出た

高速列挙を使い配列から特定の文字列を削除しようとしたら「Collection was mutated while being enumerated.」というエラーが出たのでメモで。

エラーの対処

このエラーは「列挙子を使ってアクセスしているときは配列の中身は変更しないでね」というエラーのようで、はじめは以下のような書き方をしていました。

修正前

NSMutableArray *marr = [[NSMutableArray alloc] initWithObjects: @"aaa", @"bbb", @"ccc", nil];
NSString *str= @"bbb"; 
    
for (id obj in marr) {
    if ([str isEqualToString:obj]) {
        [marr removeObject:obj];  //removeしてる
    }
}
    
NSLog(@"%@", marr);

参考記事にも書いているのですが、列挙中に配列の要素を削除すると、それより後ろにある要素すべてが「1つ前」へ移動することになり、順番に処理をしていくことができなくなってしまいます
順番に列挙処理している最中に配列の順番を変えられるとおかしくなるのは当然の結果ですね。

そこで参考記事のように、reverseObjectEnumeratorメソッドを用いて、逆順に列挙することでこのエラーを回避します。

修正後

NSMutableArray *marr = [[NSMutableArray alloc] initWithObjects: @"aaa", @"bbb", @"ccc", nil];
NSString *str= @"bbb"; 
    
for (id obj in [marr reverseObjectEnumerator]) {  //ここ
    if ([str isEqualToString:obj]) {
        [marr removeObject:obj];
    }
}
    
NSLog(@"%@", marr);

参考記事

【コラム】ダイナミックObjective-C (105) Fast Enumeration(1) - 速い列挙子 | エンタープライズ | マイナビニュース

0 件のコメント:

コメントを投稿