46

NSMutableArrayBox2d 物理シミュレーション用のマウスジョイントを格納する があります。複数の指を使用して演奏すると、次のような例外が発生します

列挙中に NSArray が変更されました

これは、配列からオブジェクトを削除しながら、それを列挙して列挙を無効にしているためです。

私が知りたいのは、これを今後解決するための最良の戦略は何ですか? 私はオンラインでいくつかの解決策を見てきました: @synchronized、列挙する前に配列をコピーするか、後で削除するためにタッチジョイントをガベージ配列に入れます(削除した直後に配列からマウスジョイントを削除する必要があるため、これが機能するかどうかはわかりません)それは世界から)。

4

10 に答える 10

48

列挙子なしでいつでも反復できます。これは通常の forループを意味し、オブジェクトを削除すると:- index 変数をデクリメントして続行します。. forループに入る前に配列のカウントをキャッシュしている場合は、オブジェクトを削除するときにそれもデクリメントしてください。

とにかく、後で削除するオブジェクトを含む配列が問題になる理由がわかりません。あなたが抱えている正確な状況と関連する技術はわかりませんが、理論的には問題はないはずです。ほとんどの場合、このメソッドを使用すると、最初の列挙では何もできず、削除配列を列挙するときに実際の作業を行うことができます。また、最初の列挙で同じ配列に対して何かをもう一度チェックしている状況があり、オブジェクトがもう存在しないことを知る必要がある場合は、それらが削除配列にあるかどうかを確認するためのチェックを追加できます。

とにかく、私が役に立てば幸いです。幸運を!

于 2012-04-14T22:06:58.737 に答える
38

次のようなことができます。

NSArray *tempArray = [yourArray copy];
for(id obj in tempArray) {
    //It's safe to remove objects from yourArray here.
}
[tempArray release];
于 2012-04-14T21:59:12.207 に答える
36

最も簡単な方法は、配列を逆方向に列挙することです。これは、オブジェクトを削除しても次のインデックスが影響を受けないことを意味します。

for (NSObject *object in [myMutableArray reverseObjectEnumerator]) {
    // it is safe to test and remove the current object      
    if (AddTestHere) {
        [myMutableArray removeObject: object];
    }
}
于 2015-07-07T12:58:53.130 に答える
6

ロック(@synchronized)操作は、配列全体を何度もコピーするよりもはるかに高速です。もちろん、これは配列に含まれる要素の数と、配列が実行される頻度によって異なります。このメソッドを同時に実行しているスレッドが10個あるとします。

- (void)Callback
{
  [m_mutableArray addObject:[NSNumber numberWithInt:3]];
  //m_mutableArray is instance of NSMutableArray declared somewhere else

  NSArray* tmpArray = [m_mutableArray copy];
  NSInteger sum = 0;
  for (NSNumber* num in tmpArray)
      sum += [num intValue];

  //Do whatever with sum
}

毎回n+1個のオブジェクトをコピーしています。ここでロックを使用できますが、反復する要素が100kある場合はどうなりますか?配列は反復が完了するまでロックされ、他のスレッドはロックが解除されるまで待機する必要があります。ここでオブジェクトをコピーする方が効果的だと思いますが、それはそのオブジェクトの大きさや反復で何をしているのかにも依存します。ロックは常に最短時間保持する必要があります。だから私はこのようなものにロックを使用します。

- (void)Callback
{
  NSInteger sum = 0;
  @synchronized(self)
  {
    if(m_mutableArray.count == 5)
      [m_mutableArray removeObjectAtIndex:4];
    [m_mutableArray insertObject:[NSNumber numberWithInt:3] atIndex:0];

    for (NSNumber* num in tmpArray)
      sum += [num intValue];
  }
  //Do whatever with sum
}
于 2013-01-22T19:18:00.960 に答える
1

列挙する代わりに for ループを使用しても問題ありません。ただし、配列要素の削除を開始したら、スレッドを使用している場合は注意してください。間違ったものを削除している可能性があるため、カウンターを減らすだけでは十分ではありません。正しい方法の 1 つは、配列のコピーを作成し、コピーを繰り返し、元の配列から削除することです。

edc1591 が正しい方法です。

[Brendt: コピーを繰り返しながらオリジナルから削除する必要があります]

于 2013-04-25T11:02:36.587 に答える
1

上記のすべては私にとってはうまくいきませんでしたが、これはうまくいきました:

 while ([myArray count] > 0) 
 {
      [<your delete method call>:[myArray objectAtIndex:0]];
 }

注:これにより、すべてが削除されます。削除する必要があるアイテムを選択する必要がある場合、これは機能しません。

于 2013-01-29T17:01:05.037 に答える
0

このエラーに遭遇しましたが、私の場合はマルチスレッドの状況が原因でした。1 つのスレッドが配列を列挙しているときに、別のスレッドが同じ配列から同時にオブジェクトを削除しました。これが誰かに役立つことを願っています。

于 2016-01-07T12:48:28.760 に答える