8

以下は私のコードです。

NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr addObject:@"5"];
[arr addObject:@"7"];
[arr addObject:@"8"];
[arr enumerateObjectsUsingBlock:^(NSString *obj,NSUInteger idx,BOOL *stop) {
        [arr replaceObjectAtIndex:idx withObject:@"10"];
}];

取得した例外ログ

 *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x742a580> was mutated while being enumerated.'
*** First throw call stack:
(0x1596012 0x12a3e7e 0x161ecc5 0x158fe1b 0x158fa16 0x158f925 0x2ba4 0x1e87b7 0x1e8da7 0x1e9fab 0x1fb315 0x1fc24b 0x1edcf8 0x25f8df9 0x25f8ad0 0x150bbf5 0x150b962 0x153cbb6 0x153bf44 0x153be1b 0x1e97da 0x1eb65c 0x29fd 0x2925)
libc++abi.dylib: terminate called throwing an exception

forループを使用している間、コードは正常に機能しています

for (int i = 0 ; i<  arr.count; i++) {
    [arr replaceObjectAtIndex:i withObject:@"8"];
}

したがって、enumerateObjectsUsingBlockを使用しているときに、例外が発生します。しかし、どちらも列挙です。右 ?では、なぜ上位コードがwas mutated while being enumerated例外を出しているのでしょうか。

4

6 に答える 6

14

あなたの論理に欠陥があるからです。列挙中にコレクションを変更することは許可されていません。後者の場合、NSMutableArray は、最初のケースでのみ、エミュレートしようとしていることを知りません。そして、これはセマンティック エラーであるため、不平を言います。通常、この種の問題は、配列を可変コピーしてコピーを変更し、元のものを更新されたコピーで置き換えることによって解決する必要があります。

于 2013-01-22T11:23:25.640 に答える
7

あなたはこれを行うことはできません:

[arr enumerateObjectsUsingBlock:^(NSString *obj,NSUInteger idx,BOOL *stop) {
        [arr replaceObjectAtIndex:idx withObject:@"10"];
}];

コレクションを列挙している間はコレクションを変更できないためです。

私の提案は、すべての操作を操作キューに入れ、列挙後にそれらを実行することです。

NSOperationQueue* queue= [NSOperationQueue new];
queue.maxConcurrentOperationCount=1;
[queue setSuspended: YES];
[arr enumerateObjectsUsingBlock:^(NSString *obj,NSUInteger idx,BOOL *stop) 
{
        NSBlockOperation* op=[NSBlockOperation blockOperationWithBlock: ^ (void)
        {
            [arr replaceObjectAtIndex:idx withObject:@"10"];
        }];     
        [queue addOperation: op];
}];
[queue setSuspended: NO];
[queue waitUntilAllOperationsAreFinished];

別の方法は、別のコレクション内のすべてのアイテムを作成し、後でそれらを削除することです。それはまた書くのが簡単でしょう。

于 2013-01-22T11:21:23.503 に答える
3

高速列挙により、コレクションは不変になります。したがって、for(.. in ..)またはを使用blockして変更しようとすると、このエラーが発生します。

コレクションをループしながら更新する必要がある場合は常に、可変コレクションを取得し、従来のfor(;;)、whileまたはdowhileループを使用する必要があります。for( .. in ..)実行時に可変コレクションを不変にします。

于 2013-01-22T11:21:18.720 に答える
3

高速列挙の使用中にコレクションを変更することはできません。役に立つはずの列挙中の変更に関する投稿を書きました。

改めて見て思ったけど、列挙しながら交換とか言ったことないな。インデックスとオブジェクトを保存してreplaceObjectsAtIndexes:withObjects:、列挙後に使用することもできます。

NSMutableArray *array = // ... 
NSMutableIndexSet *indicesForObjectsToReplace = [NSMutableIndexSet new]; 
NSMutableArray *objectsToReplace = [NSMutableArray new];

[array enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
    [indicesForObjectsToRemove addIndex:idx];
    [objectsToReplace: @"String you are replacing with"];
}]; 

[array replaceObjectsAtIndexes:indicesForObjectsToReplace
                   withObjects:objectsToReplace];
于 2013-01-22T11:27:27.233 に答える
2

休憩を追加するだけです。配列からアイテムを削除した後。

    for (NSDictionary *dic in ticketsToBuyArray) {
    if ([[[dic objectForKey:@"ticket_id"]stringValue] isEqualToString:[[ticketDictionary objectForKey:@"ticket_id"]stringValue]])
    {
        [ticketsToBuyArray removeObject:dic];
        break;
    }
}
于 2014-08-02T15:13:03.267 に答える
0

私はobjective-cの経験はあまりありませんが、これは通常、列挙型の反復間で列挙可能なオブジェクトが変更されるのを防ぐ列挙型クラスの機能です。

列挙子クラスは、コレクションから次のインスタンスを返す前に、列挙可能なオブジェクトが追加、削除、置換などの変更メソッドを実行したかどうかを確認します。また、foreachループは通常、列挙子と列挙可能なクラス(またはインターフェイス)に基づいて実装されます。

配列アイテムへのインデックス付きアクセスは、追加のメカニズムを必要としない基本的な操作であるネイティブ配列メソッドです。

于 2013-01-22T11:31:34.853 に答える