2010-01-04 16 views
60

¿Cuál es la diferencia entre copy y mutableCopy cuando se utiliza ya sea en NSArray o en NSMutableArray?¿Cómo se aplican copy y mutableCopy a NSArray y NSMutableArray?

Esto es lo que yo entiendo; ¿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 
+1

Tiene un error en su edición; seguro si es un error tipográfico o un malentendido. En el primer bloque de código, la variable myArray_imuMuta a la que está asignado desde mutableCopy es * mutable *, no inmutable como indica tu comentario. –

+0

Gracias, que era un error, que se iba a confundirse con Xcode decir "Advertencia NSArray no puede responder a añadir -addObject/-removeObjectAtIndex voy a cambiar a myArray_imuMuta NSMutableArray – fuzzygoat

+0

@JamesHarnett -.. Por favor dejar las modificaciones en el nombre de" Compatibilidad ARC "- vea [este meta post] (http://meta.stackoverflow.com/questions/268309/is-it-okay-to-convert-non-arc-objective-c-answers-to-arc) para Por qué. – Krease

Respuesta

64

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

// 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:

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

Editar: re-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.

Edición 2: fijo mi suposición (falsa) que NSMutableArray -copy devolverá un NSMutableArray.

+3

Enviar - copiar a un NSMutableArray normalmente no devuelve otra matriz mutable. Ciertamente * podría hacerlo *, pero en el caso habitual, devuelve un acceso inmutable, de tiempo constante, array. –

+0

Vaya, tiene usted razón. Leí mal el código del OP y pensé que estaba modificando el resultado de la copia. Tendría el mismo sentido que la copia de NSMutableArray para devolver otra matriz mutable, por lo que (incorrectamente) supuse que era el caso. –

+0

Me estoy perdiendo algo como Yo ca no encontrar ninguna referencia a [mut remove: @ "one"]; si esto no fuera [mut removeObjectIdenticalTo: @ "one"]; Solo quiero aclararles a los que leen esto y tratan de aprender. – fuzzygoat

8

Creo que debe 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 intentar 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 toma un parámetro NSArray *, y básicamente lo almacena para usarlo en el futuro. Usted puede hacer esto de esta manera:

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

... pero entonces usted tiene el problema de que el método puede ser llamado 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 incluso podría cambiarse mientras itera sobre él, lo que puede causar algunos errores interesantes.

Si en lugar de hacer 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 el método se llama.

6

El método de la "copia" devuelve el objeto creado mediante la implementación de NSCopying protocolos copyWithZone:

Si envía NSString un mensaje de copia:

valor
NSString* myString; 

NSString* newString = [myString copy]; 

El retorno será un NSString (no mutable)


el método mutableCopy devuelve el objeto creado mediante la implementación de mutableCopyWithZone NSMutableCopying protocolo:

Mediante el envío:

NSString* myString; 

NSMutableString* newString = [myString mutableCopy]; 

El valor de retorno SE 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 hay un nivel adicional de complejidad en cuanto 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á el 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 copiar objeto mutable

3

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

0

Supongamos contenido

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

B no es objeto NSDictionary NSMutableDictionary, ¿es correcto?

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

creará 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 un verdadero y profundo Copia podríamos utilizar,

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

Esto garantizaría que todos los niveles se copian en realidad retener la mutabilidad del objeto original en cada nivel.

Robert Clarence D'Almeida, Bangalore, India.

+0

Su concepto de "True Deep Copy" es realmente bueno. Exactamente lo que quiero ... Muchas gracias y +1 para usted ..... –

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

usted tiene que saber el tipo de retorno de estas cosas copiado y mientras declarando el nuevo objeto que se le asignará el valor de retorno debe ser de uno o mutable inmutable, de lo contrario el compilador le mostrará error.

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

2

Para decirlo simplemente,

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

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

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

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

Cuestiones relacionadas