¿Cómo hacer un bucle seguro sobre una matriz mutable mientras la modificas?

Tengo un controller que tiene una matriz con actors . Un actor es un object que será llamado por el controller .

El problema: el controller itera sobre el set de actors y envía a cada actor un -actionMessage . El actor puede crear y registrar a otro actor con el controller , o eliminar un actor o incluso él mismo de la matriz de actores del controller. Se enruta a través de dos methods:

 -registerActor:(Actor*)actor; -unregisterActor:(Actor*)actor; 

Entonces, mientras que el controller itera sobre el set de actores, la list de actores puede cambiar. Edit: Y cualquier actor recién agregado DEBE pasar por el ciclo también.

¿Cuál es la mejor práctica para hacer frente a este problema? ¿Debo crear una copy de la matriz de actores antes de repetirla?

Cree una copy de su matriz mutable e itere sobre ella.

 NSArray *loopArray = [NSArray arrayWithArray: yourActorArray]; 

O

 NSArray *loopArray = [yourActorArray copy]; //in this case remember to release in nonARC environment 

Esto es lo que suelo hacer …

 NSMutableArray *discardedItems = [NSMutableArray array]; SomeObjectClass *item; for (item in originalArrayOfItems) { if ([item shouldBeDiscarded]) [discardedItems addObject:item]; } [originalArrayOfItems removeObjectsInArray:discardedItems]; 

esperando que esto ayude.

El procedimiento estándar para enumerar a través de una matriz mutable que debe modificarse a medida que avanza es hacer una copy e iterar a través de eso, alterando el original. Supongo que el NSMutableArray de los actores es una propiedad perteneciente a su controller, y que registerActor: y unregisterActor: ambos alteran esta matriz. Si revisa una copy, puede eliminar los actores de la propiedad original a través de los methods sin alterar la copy.

 NSMutableArray *actorArrayCopy = [self.actorArray copy]; for (id object in actorArrayCopy){ //do stuff } 

En algunos casos, puede eliminar la enumeración rápida y utilizar un bucle estándar para el bucle; sin embargo, esto es arriesgado aquí. Si los objects se insertan o eliminan de la matriz, los índices cambiarán (AFAIK), lo que significa que puede terminar saltando elementos o repasando un elemento varias veces.

Algunas personas almacenan elementos para ser alterados (como eliminados) en una matriz separada dentro de la enumeración rápida y realizan todos los cambios a la vez una vez que se hace la enumeración, pero está utilizando methods separados para agregar y eliminar elementos; los elementos mismos determinan lo que debería suceder y le notifican. Esto haría las cosas más complicadas, por lo que una copy probablemente funcione mejor.

Puede evitar hacer una copy de la matriz haciendo esto:

 for(int i=0; i<[array count]; i++) { if(condition) { [array removeObjectAtIndex:i]; i --; continue; } } 

Debe usar un set en lugar de una matriz. Luego puede copyr el set y, una vez que se haya realizado la operación, tome un diff para ver qué ha cambiado.

Deberías usar lo normal para bucle como

 for ( ''initializer''; ''conditional expression''; ''loop expression'' ) { // statements to be executed } 

No use rápido / objective -c para bucle. Le permitirá editar la matriz …