¿Cómo se aplican copy y mutableCopy a NSArray y NSMutableArray?

¿Cuál es la diferencia entre copy y mutableCopy cuando se utiliza en un NSArray o en un NSMutableArray ?

Este es mi entendimiento; ¿es correcto?

 // ** NSArray ** NSArray *myArray_imu = [NSArray arrayWithObjects:@"abc", @"def", nil]; // No copy, increments retain count, result is immutable NSArray *myArray_imuCopy = [myArray_imu copy]; // Copys object, result is mutable NSArray *myArray_imuMuta = [myArray_imu mutableCopy]; // Both must be released later 

 // ** NSMutableArray ** NSMutableArray *myArray_mut = [NSMutableArray arrayWithObjects:@"A", @"B", nil]; // Copys object, result is immutable NSMutableArray *myArray_mutCopy = [myArray_mut copy]; // Copys object, result is mutable NSMutableArray *myArray_mutMuta = [myArray_mut mutableCopy]; // Both must be released later 

copy y mutableCopy se definen en diferentes protocolos ( NSCopying y NSMutableCopying , respectivamente) y NSArray ajusta a ambos. mutableCopy se define para NSArray (no solo NSMutableArray ) y le permite hacer una copia mutable de una matriz inmutable originalmente:

 // create an immutable array NSArray *arr = [NSArray arrayWithObjects: @"one", @"two", @"three", nil ]; // create a mutable copy, and mutate it NSMutableArray *mut = [arr mutableCopy]; [mut removeObject: @"one"]; 

Resumen:

  • puede depender del resultado de mutableCopy para ser mutable, independientemente del tipo original. En el caso de las matrices, el resultado debería ser un NSMutableArray .
  • ¡ no puede depender del resultado de la copy para ser mutable! copy un NSMutableArray puede devolver un NSMutableArray , ya que esa es la clase original, pero copy cualquier instancia arbitraria de NSArray no lo haría.

Editar: vuelva a leer su código original a la luz de la respuesta de Mark Bessey. Cuando crea una copia de su matriz, por supuesto, puede modificar el original independientemente de lo que haga con la copia. copy vs mutableCopy afecta si la nueva matriz es mutable.

Editar 2: Se NSMutableArray -copy mi suposición (falsa) de que NSMutableArray -copy devolvería un NSMutableArray .

Creo que debes haber malinterpretado cómo funcionan copy y mutableCopy. En su primer ejemplo, myArray_COPY es una copia inmutable de myArray. Una vez realizada la copia, puede manipular el contenido del archivo myArray original y no afectar el contenido de myArray_COPY.

En el segundo ejemplo, crea una copia mutable de myArray, lo que significa que puede modificar cualquiera de las copias de la matriz, sin afectar la otra.

Si cambio el primer ejemplo para tratar de insertar / eliminar objetos de myArray_COPY, falla, tal como era de esperar.


Tal vez pensar en un caso de uso típico ayudaría. A menudo ocurre que puede escribir un método que tome un parámetro NSArray * , y básicamente lo almacene para su uso posterior. Podrías hacer esto de esta manera:

 - (void) doStuffLaterWith: (NSArray *) objects { myObjects=[objects retain]; } 

… pero luego tiene el problema de que se puede llamar al método con un NSMutableArray como argumento. El código que creó la matriz puede manipularlo cuando se llama al método doStuffLaterWith: y cuando más tarde necesita usar el valor. En una aplicación de subprocesos múltiples, el contenido de la matriz podría incluso cambiarse mientras se itera sobre él , lo que puede causar algunos errores interesantes.

Si en cambio haces esto:

 - (void) doStuffLaterWith: (NSArray *) objects { myObjects=[objects copy]; } 

..then la copia crea una instantánea de los contenidos de la matriz en el momento en que se llama al método.

El método “copiar” devuelve el objeto creado mediante la implementación de protocolos NSCopying copyWithZone:

Si envía NSString un mensaje de copia:

 NSString* myString; NSString* newString = [myString copy]; 

El valor de retorno será un NSString (no mutable)


El método mutableCopy devuelve el objeto creado al implementar el protocolo mutableCopyWithZone del protocolo NSMutableCopying:

Enviando:

 NSString* myString; NSMutableString* newString = [myString mutableCopy]; 

El valor de retorno SERÁ mutable.


En todos los casos, el objeto debe implementar el protocolo, lo que significa que creará el nuevo objeto de copia y se lo devolverá.


En el caso de NSArray existe un nivel extra de complejidad con respecto a la copia superficial y profunda.

Una copia superficial de un NSArray solo copiará las referencias a los objetos de la matriz original y los colocará en la nueva matriz.

El resultado es que:

 NSArray* myArray; NSMutableArray* anotherArray = [myArray mutableCopy]; [[anotherArray objectAtIndex:0] doSomething]; 

También afectará al objeto en el índice 0 en la matriz original.


Una copia profunda realmente copiará los objetos individuales contenidos en la matriz. Esto se hace enviando a cada objeto individual el mensaje “copyWithZone:”.

 NSArray* myArray; NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:myArray copyItems:YES]; 

Editado para eliminar mi suposición errónea sobre la copia de objetos mutables

 NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES]; 

creará otro anotherArray que es una copia de oldArray a 2 niveles de profundidad. Si un objeto de oldArray es una matriz. Que es generalmente el caso en la mayoría de las aplicaciones.

Bueno, si necesitamos una True Deep Copy , podríamos usar

 NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject: oldArray]]; 

Esto garantizaría que todos los niveles se copien efectivamente conservando la mutabilidad del objeto original en cada nivel.

Robert Clarence D’Almeida, Bangalore, India.

Está llamando addObject y removeObjectAtIndex en la matriz original, en lugar de la nueva copia que ha realizado. La copia de llamada frente a mutableCopy solo afecta la mutabilidad de la nueva copia del objeto, no el objeto original.

Para decirlo simplemente,

  • copia devuelve una copia inmutable (no se puede modificar) de la matriz,
  • mutableCopy devuelve una copia mutable (se puede modificar) de la matriz.

Copiar (en ambos casos) significa que obtiene una nueva matriz “poblada” con referencias de objetos a la matriz original (es decir, se hace referencia a los mismos objetos (originales) en las copias.

Si agrega nuevos objetos a mutableCopy, entonces son exclusivos de mutableCopy. Si elimina objetos de mutableCopy, se eliminan de la matriz original.

Piense en la copia en ambos casos, como una instantánea en el tiempo de la matriz original en el momento en que se creó la copia.

Asumir

 NSArray *A = xxx; // A with three NSDictionary objects NSMutableArray *B = [A mutableCopy]; 

El contenido de B es NSDictionary object no NSMutableDictionary, ¿es correcto?

 -(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that's it. 

Debe conocer el tipo de devolución de estas copias y, al declarar el nuevo objeto al que se asignará, el valor devuelto debe ser inmutable o mutable, de lo contrario el comstackdor mostrará el error.

El objeto que se ha copiado no se puede modificar con el nuevo, ahora son dos objetos totalmente diferentes.