Existe alguma função incorporada que me permite copiar em profundidade um NSMutableArray
?
Olhei em volta, algumas pessoas dizem que [aMutableArray copyWithZone:nil]
funciona como cópia profunda. Mas tentei e parece ser uma cópia superficial.
No momento, estou fazendo a cópia manualmente com um for
loop:
//deep copy a 9*9 mutable array to a passed-in reference array
-deepMuCopy : (NSMutableArray*) array
toNewArray : (NSMutableArray*) arrayNew {
[arrayNew removeAllObjects];//ensure it's clean
for (int y = 0; y<9; y++) {
[arrayNew addObject:[NSMutableArray new]];
for (int x = 0; x<9; x++) {
[[arrayNew objectAtIndex:y] addObject:[NSMutableArray new]];
NSMutableArray *aDomain = [[array objectAtIndex:y] objectAtIndex:x];
for (int i = 0; i<[aDomain count]; i++) {
//copy object by object
NSNumber* n = [NSNumber numberWithInt:[[aDomain objectAtIndex:i] intValue]];
[[[arrayNew objectAtIndex:y] objectAtIndex:x] addObject:n];
}
}
}
}
mas gostaria de uma solução mais limpa e sucinta.
objective-c
cocoa-touch
cocoa
nsarray
deep-copy
Ivan, o Terrível
fonte
fonte
-copy
coleções imutáveis mudou entre o Mac OS X 10.4 e 10.5: developer.apple.com/library/mac/releasenotes/Cocoa/… (role para baixo até "Coleções imutáveis e comportamento de cópia")copy
, o que deve ser colocado na "cópia profunda"? Se o elemento for outra coleção,copy
na verdade não produz uma cópia (da mesma classe). Portanto, acho perfeitamente válido argumentar sobre o tipo de cópia desejada no caso específico.NSCopying
/-copy
, então ele não pode ser copiado - então você nunca deve tentar fazer uma cópia dele, porque esse não é um recurso para o qual ele foi projetado. Em termos de implementação do Cocoa, objetos não copiáveis geralmente têm algum estado de back-end C ao qual estão vinculados, portanto, hackear uma cópia direta do objeto pode levar a condições de corrida ou pior. Portanto, para responder “o que deve ser colocado na 'cópia profunda'” - Uma ref retida. A única coisa que você pode colocar em qualquer lugar quando você tem um não-NSCopying
objeto.Respostas:
Como a documentação da Apple sobre cópias profundas afirma explicitamente:
O código acima cria uma nova matriz cujos membros são cópias superficiais dos membros da matriz antiga.
Observe que se você precisar copiar profundamente uma estrutura de dados aninhada inteira - o que os documentos vinculados da Apple chamam de cópia verdadeira e profunda - essa abordagem não será suficiente. Por favor, veja as outras respostas aqui para isso.
fonte
copyWithZone:
é implementada na classe receptora.A única maneira que conheço de fazer isso facilmente é arquivar e desarquivar imediatamente seu array. Parece um hack, mas na verdade é explicitamente sugerido na Documentação da Apple sobre cópias de coleções , que afirma:
O problema é que seu objeto deve suportar a interface NSCoding, uma vez que ela será usada para armazenar / carregar os dados.
Versão Swift 2:
fonte
initWithArray:copyItems:
método? Esta solução alternativa de arquivamento / desarquivamento parece muito útil, considerando quantas classes de controle estão em conformidade com NSCoding, mas não com NSCopying.Copiar por padrão fornece uma cópia superficial
Isso ocorre porque chamar
copy
é o mesmo quecopyWithZone:NULL
também conhecido como copiar com a zona padrão. Acopy
chamada não resulta em uma cópia profunda. Na maioria dos casos, isso lhe daria uma cópia superficial, mas em qualquer caso, depende da classe. Para uma discussão completa, recomendo os Tópicos de programação de coleções no site do desenvolvedor da Apple.initWithArray: CopyItems: fornece uma cópia profunda de um nível
NSCoding
é a maneira recomendada pela Apple de fornecer uma cópia detalhadaPara uma cópia verdadeira em profundidade (Array of Arrays), você precisará
NSCoding
arquivar / desarquivar o objeto:fonte
Para Dictonário
NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);
Para Array
NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);
fonte
Não, não há algo embutido nas estruturas para isso. As coleções de cacau suportam cópias superficiais (com os métodos
copy
ouarrayWithArray:
), mas nem mesmo falam sobre o conceito de cópia profunda.Isso ocorre porque a "cópia profunda" começa a se tornar difícil de definir conforme o conteúdo de suas coleções começa a incluir seus próprios objetos personalizados. "Cópia profunda" significa que cada objeto no gráfico de objeto é uma referência única em relação a cada objeto no gráfico de objeto original?
Se houvesse algum
NSDeepCopying
protocolo hipotético , você poderia configurá-lo e tomar decisões em todos os seus objetos, mas infelizmente não existe. Se você controlar a maioria dos objetos em seu gráfico, poderá criar esse protocolo sozinho e implementá-lo, mas precisará adicionar uma categoria às classes Foundation conforme necessário.A resposta de @AndrewGrant sugerindo o uso de arquivamento / desarquivamento com chave é uma forma sem desempenho, mas correta e limpa de conseguir isso para objetos arbitrários. Este livro vai tão longe, então sugiro adicionar uma categoria a todos os objetos que faz exatamente isso para oferecer suporte a cópias profundas.
fonte
Eu tenho uma solução alternativa se tentar obter uma cópia profunda para dados compatíveis com JSON.
Basta ter
NSData
deNSArray
usarNSJSONSerialization
e, em seguida, recriar JSON objeto, isso vai criar uma cópia nova e fresca completa deNSArray/NSDictionary
novas referências de memória deles.Mas certifique-se de que os objetos de NSArray / NSDictionary e seus filhos devem ser serializáveis em JSON.
fonte
NSJSONReadingMutableContainers
para o caso de uso nesta questão.