¿Hay alguna función incorporada que me permita realizar una copia profunda NSMutableArray
?
Miré a mi alrededor, algunas personas dicen que [aMutableArray copyWithZone:nil]
funciona como una copia profunda. Pero lo intenté y parece ser una copia superficial.
En este momento estoy haciendo la copia manualmente con un for
bucle:
//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];
}
}
}
}
pero me gustaría una solución más limpia y concisa.
objective-c
cocoa-touch
cocoa
nsarray
deep-copy
Ivan el Terrible
fuente
fuente
-copy
colecciones inmutables cambió entre Mac OS X 10.4 y 10.5: developer.apple.com/library/mac/releasenotes/Cocoa/… (desplácese hacia abajo hasta "Colecciones inmutables y comportamiento de copia")copy
, ¿qué se incluirá en la "copia profunda"? Si el elemento es otra colección, encopy
realidad no produce una copia (de la misma clase). Así que creo que es perfectamente válido discutir sobre el tipo de copia que se desea en el caso específico.NSCopying
/-copy
, entonces no se puede copiar, por lo que nunca debe intentar hacer una copia, porque esa no es una capacidad para la que fue diseñado. En términos de la implementación de Cocoa, los objetos no copiables a menudo tienen algún estado de backend C al que están vinculados, por lo que piratear una copia directa del objeto podría generar condiciones de carrera o algo peor. Entonces, para responder “lo que se pondrá en la 'copia profunda'” - Se retuvo una ref. Lo único que puede poner en cualquier lugar cuando tiene un noNSCopying
objeto.Respuestas:
Como dice explícitamente la documentación de Apple sobre copias profundas :
El código anterior crea una nueva matriz cuyos miembros son copias superficiales de los miembros de la matriz anterior.
Tenga en cuenta que si necesita copiar profundamente una estructura de datos anidada completa, lo que los documentos de Apple vinculados llaman una copia profunda verdadera , este enfoque no será suficiente. Consulte las otras respuestas aquí para eso.
fuente
copyWithZone:
se implemente en la clase receptora.La única forma que conozco de hacer esto fácilmente es archivar y luego desarchivar inmediatamente su matriz. Se siente como un truco, pero en realidad se sugiere explícitamente en la Documentación de Apple sobre la copia de colecciones , que dice:
El problema es que su objeto debe ser compatible con la interfaz NSCoding, ya que se utilizará para almacenar / cargar los datos.
Versión Swift 2:
fuente
initWithArray:copyItems:
método? Esta solución de archivar / desarchivar parece muy útil, considerando cuántas clases de control se ajustan a NSCoding pero no a NSCopying.Copiar por defecto da una copia superficial
Esto se debe a que llamar
copy
es lo mismo quecopyWithZone:NULL
también se conoce como copiar con la zona predeterminada. Lacopy
llamada no da como resultado una copia profunda. En la mayoría de los casos le daría una copia superficial, pero en cualquier caso depende de la clase. Para una discusión exhaustiva, recomiendo los temas de programación de colecciones en el sitio para desarrolladores de Apple.initWithArray: CopyItems: proporciona una copia profunda de un nivel
NSCoding
es la forma recomendada por Apple de proporcionar una copia detalladaPara una verdadera copia profunda (Array of Arrays), necesitará
NSCoding
y archivar / desarchivar el objeto:fuente
Para Dictonary
NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);
Para matriz
NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);
fuente
No, no hay nada integrado en los marcos para esto. Las colecciones de Cocoa admiten copias superficiales (con los métodos
copy
oarrayWithArray:
), pero ni siquiera hablan de un concepto de copia profunda.Esto se debe a que la "copia profunda" comienza a ser difícil de definir a medida que el contenido de sus colecciones comienza a incluir sus propios objetos personalizados. ¿"Copia profunda" significa que cada objeto en el gráfico de objetos es una referencia única relativa a cada objeto en el gráfico de objetos original?
Si hubiera algún
NSDeepCopying
protocolo hipotético , podría configurarlo y tomar decisiones en todos sus objetos, pero desafortunadamente no lo hay. Si controlaste la mayoría de los objetos en tu gráfico, podrías crear este protocolo tú mismo e implementarlo, pero necesitarías agregar una categoría a las clases Foundation según sea necesario.La respuesta de @ AndrewGrant que sugiere el uso de archivado / desarchivado por clave es una forma no funcional pero correcta y limpia de lograr esto para objetos arbitrarios. Este libro incluso llega tan lejos, por lo que sugiere agregar una categoría a todos los objetos que haga exactamente eso para respaldar la copia profunda.
fuente
Tengo una solución alternativa si intento lograr una copia profunda para datos compatibles con JSON.
Simplemente toma
NSData
deNSArray
usarNSJSONSerialization
y volver a crear objetos JSON, esto creará una copia completa de nuevo y frescoNSArray/NSDictionary
con nuevas referencias a la memoria de ellos.Pero asegúrese de que los objetos de NSArray / NSDictionary y sus hijos deben ser serializables en JSON.
fuente
NSJSONReadingMutableContainers
el caso de uso en esta pregunta.