2012-01-12 14 views
36

Me topé con el error en el que intentas eliminar objetos de un NSMutableArray mientras otros objetos se agregan a él en otro lugar. Para hacerlo simple, no tengo idea de cómo solucionarlo. Esto es lo que estoy haciendo:Objective-C NSMutableArray mutó mientras se enumeraba?

Tengo 4 temporizadores llamando a 4 métodos diferentes que agregan un objeto a la misma matriz. Ahora, cuando presiono un cierto botón, necesito eliminar todos los objetos en el conjunto (o al menos algunos). Así que traté de invalidar primero los 4 temporizadores, y luego hacer el trabajo que quiero con la matriz, y luego encender los temporizadores. Pensé que esto hubiera funcionado ya que no estoy usando los temporizadores para enumerar a través de la matriz, pero aparentemente no funciona.

¿Alguna sugerencia aquí?

+0

Esto también me está sucediendo, pero no estoy eliminando nada de mi NSMutableArray. Sin embargo, estoy agregando elementos en un hilo de fondo. Solo arroja este error quizás una vez cada 50 o 100, agrega ... y este es el único hilo que alguna vez toca la matriz en la aplicación completa ... – Jesse

Respuesta

103

No tiene nada que ver con sus temporizadores. Debido a que (supongo) que sus temporizadores funcionan todos con el mismo hilo que su método de modificación, no es necesario detenerlos e iniciarlos. iOS no utilizar un modelo de interrupción de las rutinas de temporización, que tienen que esperar su turno al igual que cualquier otro evento :)

Probablemente esté haciendo algo como

for (id object in myArray) 
    if (someCondition) 
     [myArray removeObject:object]; 

No se puede editar un mutable gama, mientras que usted va a través de él por lo que necesita para hacer un arreglo temporal para mantener las cosas que desea eliminar

// Find the things to remove 
NSMutableArray *toDelete = [NSMutableArray array]; 
for (id object in myArray) 
    if (someCondition) 
     [toDelete addObject:object]; 

// Remove them 
[myArray removeObjectsInArray:toDelete]; 
+0

Creo que las últimas dos líneas deberían leer "' para (objeto id en toDelete) [myArray removeObject: object]; '" –

+0

@ TobiasKlüpfel - tienes toda la razón - He editado mi respuesta. – deanWombourne

+0

Simplemente use '-removeObjectsInArray:'. Además, si accede a través de índices, puede modificarlo mientras itera sobre él. –

22

puede hacerlo de esta manera:

for (id object in [myArray copy]) 
    if (someCondition) 
     [myArray removeObject:object]; 

Como @deanWombourne dijo, "no puedes editar una matriz mutable mientras la estás pasando", así que lo que estoy haciendo aquí es crear una copia liberada automáticamente de tu matriz original para enumerar los objetos, para que puedas puede eliminar de forma segura todo lo que quieras.

Más claro y menos código de caldera (¡creo!).

Actualización: Se ha eliminado la llamada de liberación automática, ya que esta era una respuesta antigua, pre ARC.

+0

Muy bien :) Podría ser un problema de rendimiento si tu 'myArray' es muy grande y solo estás eliminando algunos artículos pero ciertamente me gusta su elegancia! – deanWombourne

+0

Lo más elegante aquí, y por supuesto 'autorelease' no es necesario con ARC. – mojuba

+0

Además del problema de rendimiento @deanWombourne mencionado anteriormente, el uso de '[myArray copy]' para cada iteración podría ralentizar su programa. Recomiendo crear una instancia de 'NSArray' (por ejemplo,' NSArray * tempArray = [mi copia de Array]; ') antes del bucle for y usar eso en su lugar. – pxpgraphics

0

Aunque por encima de todo son verdad ... Me gustaría compartir mi experiencia con

mutado mientras que siendo enumerado

Lo que estaba haciendo era sencilla pero totalmente llena de errores:

for (id obj in d.dataDashBoardGraph) { 
    [tmpData addObject:[obj valueForKey:[[dataToShow[i] componentsSeparatedByString:@"_"] objectAtIndex:1]]]; 

    ... 
} 

Incluso esto causó mutated being enumerated error. Para deshacerse de él:

for (id obj in d.dataDashBoardGraph) { 
    NSString *data = [dataToShow[i] copy]; 
    [tmpData addObject:[obj valueForKey:[[data componentsSeparatedByString:@"_"] objectAtIndex:1]]]; 

    ... 
} 

Luego funcionó a la perfección.

-1

NSMutableArray no se puede mutar mientras son enumerados, es posible crear una pequeña demora antes de llamar a su acción:

for(id key in resultsDictionary) { 
       if ([key isEqual:whichButtonString]) { 
        // [resultsDictionary removeObjectForKey:whichButtonString]; 
        [self performSelector:@selector(removeKeyFromDictionary:) withObject:whichButtonString afterDelay:1.0]; 
       } 
      } 

Entonces

-(void) removeKeyFromDictionary : (NSString *) incomingString { 
[resultsDictionary removeObjectForKey:incomingString]; 

}

0

Usted puede tratar de:

for (id object in [myArray reverseObjectEnumerator]) 
if (someCondition) 
    [myArray removeObject:object]; 

Si elimina objeto en el índice x => El índice de objetos en el índice x + 1, x + 2 .... se cambiará. Por lo tanto, cuando usa reverseObjectEnumerator, el índice de objetos en el conjunto después de eliminar algunos objetos aún corregirá.

Espero que esta ayuda. (la respuesta aceptada es una solución clara.)

Cuestiones relacionadas