Como copy e mutableCopy se aplicam a NSArray e NSMutableArray?

Qual é a diferença entre copy e mutableCopy quando usado em um NSArray ou em um NSMutableArray ?

Este é meu entendimento; está correto?

 // ** 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 e mutableCopy são definidos em protocolos diferentes ( NSCopying e NSMutableCopying , respectivamente) e o NSArray está em conformidade com ambos. mutableCopy é definido para NSArray (não apenas NSMutableArray ) e permite criar uma cópia mutável de uma matriz originalmente imutável:

 // 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"]; 

Resumo:

  • você pode depender do resultado de mutableCopy para ser mutável, independentemente do tipo original. No caso de matrizes, o resultado deve ser um NSMutableArray .
  • você não pode depender do resultado da copy para ser mutável! copy um NSMutableArray pode retornar um NSMutableArray , uma vez que essa é a class original, mas copy qualquer instância arbitrária de NSArray não.

Editar: releia o seu código original à luz da resposta de Mark Bessey. Quando você cria uma cópia de sua matriz, é claro que ainda é possível modificar o original, independentemente do que você faz com a cópia. copy vs mutableCopy afeta se o novo array é mutável.

Editar 2: Corrigida minha suposição (falsa) de que NSMutableArray -copy retornaria um NSMutableArray .

Eu acho que você deve ter interpretado mal como copy e mutableCopy funcionam. Em seu primeiro exemplo, myArray_COPY é uma cópia imutável de myArray. Tendo feito a cópia, você pode manipular o conteúdo do myArray original e não afetar o conteúdo de myArray_COPY.

No segundo exemplo, você cria uma cópia mutável de myArray, o que significa que você pode modificar uma cópia da matriz sem afetar a outra.

Se eu alterar o primeiro exemplo para tentar inserir / remover objects de myArray_COPY, ele falhará, assim como você esperaria.


Talvez pensar em um caso de uso típico ajudaria. Geralmente é o caso de você escrever um método que usa um parâmetro NSArray * e basicamente o armazena para uso posterior. Você poderia fazer isso desta maneira:

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

… mas então você tem o problema que o método pode ser chamado com um NSMutableArray como argumento. O código que criou o array pode manipulá-lo entre quando o método doStuffLaterWith: é chamado e quando mais tarde você precisar usar o valor. Em um aplicativo multi-threaded, o conteúdo do array pode até ser alterado enquanto você está interagindo com ele , o que pode causar alguns bugs interessantes.

Se você fizer isso:

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

..a seguir, a cópia cria um instantâneo do conteúdo da matriz no momento em que o método é chamado.

O método “copy” retorna o object criado pela implementação dos protocolos NSCopying copyWithZone:

Se você enviar NSString uma mensagem de cópia:

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

O valor de retorno será um NSString (não mutável)


O método mutableCopy retorna o object criado pela implementação do mutableCopyWithZone do protocolo NSMutableCopying:

Enviando:

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

O valor de retorno será mutável.


Em todos os casos, o object deve implementar o protocolo, significando que ele criará o novo object de cópia e o retornará a você.


No caso do NSArray, existe um nível extra de complexidade em relação à cópia superficial e profunda.

Uma cópia superficial de um NSArray copiará apenas as referências aos objects do array original e os colocará no novo array.

O resultado é que:

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

Também afetará o object no índice 0 na matriz original.


Uma cópia profunda irá copiar os objects individuais contidos na matriz. Isto feito enviando cada object individual a mensagem “copyWithZone:”.

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

Editado para remover minha suposição errada sobre cópia de object mutável

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

irá criar anotherArray que é uma cópia do oldArray para 2 níveis de profundidade. Se um object do oldArray for um Array. Qual é geralmente o caso na maioria das aplicações.

Bem, se precisarmos de uma True Deep Copy , poderíamos usar

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

Isso garantiria que todos os níveis sejam realmente copiados, mantendo a mutabilidade do object original em cada nível.

Robert Clarence D’Almeida, Bangalore, Índia.

Você está chamando addObject e removeObjectAtIndex na matriz original, em vez da nova cópia que você fez. Chamar copy vs mutableCopy afeta apenas a mutabilidade da nova cópia do object, não o object original.

Para declará-lo simplesmente,

  • copy retorna uma cópia imutável (não pode ser modificada) da matriz,
  • mutableCopy retorna uma cópia mutável (pode ser modificada) da matriz.

Copiar (em ambos os casos) significa que você obtém uma nova matriz “preenchida” com referências de object para a matriz original (isto é, os mesmos objects (originais) são referenciados nas cópias.

Se você adicionar novos objects ao mutableCopy, eles serão exclusivos do mutableCopy. Se você remover objects do mutableCopy, eles serão removidos do array original.

Pense na cópia em ambos os casos, como um instantâneo no tempo da matriz original no momento em que a cópia foi criada.

Assumir

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

O conteúdo de B é o object NSDictionary e não o NSMutableDictionary, certo?

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

Você tem que saber o tipo de retorno desses materiais de cópia e ao declarar o novo object qual deles será atribuído o valor de retorno deve ser imutável ou mutável, caso contrário, o compilador mostrará erro.

O object que foi copiado não pode ser modificado usando o novo, eles são totalmente dois objects diferentes agora.