Pergunta

Existe alguma função built-in que me permite copiar profunda um NSMutableArray?

Eu olhei ao redor, algumas pessoas dizem obras [aMutableArray copyWithZone:nil] como cópia profunda. Mas eu tentei e parece ser uma cópia superficial.

Agora eu estou fazendo manualmente a cópia com um laço for:

//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 eu gostaria de uma mais limpa, solução mais sucinto.

Foi útil?

Solução

Como o docs da Apple estado,

Se você só precisa de uma cópia de um nível de profundidade, você pode explicitamente chamar a ...

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

O código acima cria uma nova matriz cujos membros são cópias rasas dos membros da matriz de idade.

Note que se você precisa copiar profundamente toda uma estrutura de dados aninhada - o que os docs da Apple ligados chamar um "cópia profunda" - então esta abordagem não será suficiente - veja as outras respostas aqui.

Outras dicas

A única forma que conheço para fazer isso facilmente é para arquivar e logo em seguida desarquivar a sua matriz. Ela se sente como um pouco de um truque, mas na verdade é explicitamente sugerido na documentação da Apple sobre como copiar coleções , que afirma:

Se precisar de uma cópia profunda, como quando você tem uma matriz de matrizes, você pode arquivar e desarquivar a coleção, desde que os conteúdos estão todos em conformidade com o protocolo NSCoding. Um exemplo desta técnica é mostrada na Listagem 3.

A Listagem 3 Um verdadeiro cópia profunda

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

O problema é que o objeto deve suportar a interface NSCoding, uma vez que este será usado para armazenar / carregar os dados.

Swift 2 Versão:

let trueDeepCopyArray = NSKeyedUnarchiver.unarchiveObjectWithData(
    NSKeyedArchiver.archivedDataWithRootObject(oldArray))

Copiar por padrão dá uma cópia superficial

Isso é porque chamando copy é o mesmo que copyWithZone:NULL também conhecida como a cópia com a zona padrão. A chamada copy não resulta em uma cópia profunda. Na maioria dos casos que lhe daria uma cópia superficial, mas em qualquer caso, depende da classe. Para uma discussão aprofundada Eu recomendo o Collections Programação Tópicos no site Apple Developer.

initWithArray: CopyItems: dá um nível de uma profunda copiar

NSArray *deepCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES];

NSCoding é o da Apple recomendado maneira de fornecer um profundo cópia

Para uma cópia profunda (Array de Arrays) você precisará NSCoding e arquivar / desarquivar o objeto:

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

Para Dictonary

NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);

Para array

NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);

Não, não é algo construído nos quadros para isso. colecções de cacau apoiar cópias rasas (com a copy ou os métodos arrayWithArray:), mas nem sequer falar sobre um conceito cópia profunda.

Isto porque "cópia profunda" começa a se tornar difícil de definir como o conteúdo de suas coleções começar incluindo seus próprios objetos personalizados. Faz "cópia profunda" média todas objeto no gráfico de objeto é uma referência única em relação ao todas objeto no gráfico do objeto original?

Se houve algum protocolo NSDeepCopying hipotética, você pode configurá-lo e tomar decisões em todos os seus objetos, mas infelizmente não é. Se você controlava a maior parte dos objetos em seu gráfico, você pode criar este protocolo si mesmo e implementá-lo, mas você precisa adicionar uma categoria para as classes Foundation conforme necessário.

@ do AndrewGrant resposta sugerindo o uso de chaveta arquivamento / desarquivando é uma maneira nonperformant mas correto e limpo de conseguir isso para objetos arbitrários. Este livro vai mesmo tão longe assim, sugerem adicionar uma categoria para todos os objetos que faz exatamente isso para apoiar a cópia profunda.

Eu tenho uma solução alternativa se tentando alcançar cópia profunda de dados compatível JSON.

Basta ter NSData de NSArray usando NSJSONSerialization e recrie JSON objeto, isso vai criar uma cópia nova e fresca completa de NSArray/NSDictionary com novas referências memória deles.

Mas certifique-se os objetos de NSArray / NSDictionary e seus filhos deve ser JSON serializado.

NSData *aDataOfSource = [NSJSONSerialization dataWithJSONObject:oldCopy options:NSJSONWritingPrettyPrinted error:nil];
NSDictionary *aDictNewCopy = [NSJSONSerialization JSONObjectWithData:aDataOfSource options:NSJSONReadingMutableLeaves error:nil];
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top