La diferencia entre retención y copia en iOS
Copiar crea un nuevo objeto, retener crea un puntero y el recuento de objetos de referencia aumenta en 1. El atributo Copiar indica que el contenido de los dos objetos es el mismo. El nuevo objeto conserva 1, lo que no tiene nada que ver con el recuento de referencias del objeto antiguo. La replicación reduce la dependencia de un objeto del contexto.
El atributo de retención indica que los dos objetos tienen la misma dirección (crea un puntero y copia el puntero) y, por supuesto, el contenido es el mismo. El valor de retención de este objeto es 1, es decir, retener es una copia del puntero y la copia es una copia del contenido.
Por supuesto, en ios, no todos los objetos admiten copia y copia mutable. Las clases que se ajustan al protocolo NSCopying pueden enviar mensajes de copia, y las clases que se ajustan al protocolo NSMutableCopying pueden enviar mensajes de copia mutables. Se produce una excepción si la copia o copia mutable enviada no se ajusta a ambos protocolos de apelación. Sin embargo, las clases predeterminadas de iOS no se ajustan a estos dos protocolos. Si desea personalizar la copia, debe cumplir con NSCopying e implementar el método copyWithZone:. Si desea personalizar mutableCopy, debe cumplir con mutableCopy e implementar el método mutableCopyWithZone:.
En primer lugar, necesitamos tener la siguiente premisa:
[array add object: obj]
De esta manera, el recuento de referencias de obj; se incrementará en 1. Si usa eliminar, el recuento de referencia de obj se reducirá en 1.
Así es como iOS maneja las colecciones en la memoria.
Entonces, suponiendo que obj sea propiedad únicamente de la matriz:
id temp = [array objectAtIndex: 0]
[array removeObjectAtIndex:
; p >Si intentas usar temp nuevamente, obtendrás un error porque obj ya ha sido liberado.
(Como recordatorio, si usa NSString para realizar pruebas, tenga en cuenta que @"ABC" es una constante :-))
Porque los valores de las clases de colección a menudo son pasa por el programa, por lo que la retención simple puede no ser suficiente y también se requiere una copia del contenido de la colección, es decir, una copia profunda.
Vamos a comentarlo a continuación.
Ios proporciona métodos de copia y copia mutable. Como sugiere el nombre, copiar copia un objeto inmutable, mientras que mutablecopy copia un objeto mutable. A continuación se darán algunos ejemplos para ilustrar.
1. Objetos del sistema que no son contenedores
Esto se refiere a objetos como NSString y NSNumber.
ns cadena * cadena = @"origen";
ns cadena * copia de cadena =[copia de cadena]
NSMutableString * copia de cadena =[cadena mutable] copiar];
[string copy append string:@"!!"];
Mirando la memoria, podemos encontrar que string y stringCopy apuntan a la misma área de memoria (también conocido como cita débil de Apple). En este momento, los recuentos de referencias de stringCopy y string son 2. StringMCopy es lo que llamamos una copia real. El sistema le asignará nueva memoria, pero la cadena a la que apunta el puntero sigue siendo la misma que la cadena a la que apunta la cadena.
Consulte el siguiente ejemplo:
NSMutableString * string =[NSMutableString string withstring:@"origin"];
ns string * string copy =[string copiar];
NSMutableString * mStringCopy = [copia de cadena];
NSMutableString * copia de cadena = [copia de cadena mutable]
[mStringCopy appendString: @" mm"]; //Error
[cadena agregar cadena: @"origen "];
[cadena copiar agregar cadena: @"!"];
p >La memoria asignada por los cuatro objetos NSString anteriores es diferente. Pero para mStringCopy, en realidad es un objeto inmutable, por lo que se informará un error arriba.
Para los objetos que no son contenedores del sistema, podemos pensar que si copiamos un objeto inmutable, la copia es una copia de puntero (copia superficial) y mutableCopy es una copia de objeto (copia profunda). Si copia objetos mutables, son copias profundas, pero los objetos devueltos por la copia son inmutables.
2. Objetos de clase contenedora del sistema
Consulte NSArray, NSDictionary, etc. Para la clase de contenedor en sí, las conclusiones discutidas anteriormente también se aplican. Lo que es necesario discutir son los cambios en los objetos en el contenedor después de la copia.
//copy devuelve un objeto inmutable y mutablecopy devuelve un objeto mutable.
NSArray * matriz 1 = [NSArray arrayWithObjects: @"a", @"b", @"c", nil];
NSArray * copia de matriz 1 = [matriz 1 copy】;
//arrayCopy1 y array son el mismo objeto NSarray (apuntando al mismo objeto), y los elementos de la matriz también apuntan al mismo puntero.
NSLog (@"matriz 1 retiene recuento: d", [matriz 1 retiene recuento]
NSLog (@"matriz 1 retiene recuento: d", [matriz copia 1); retener recuento]);
NSMutableArray * marray copy 1 =[array 1 mutable copy];
//ArrayCopy 1 es una copia variable de array1, que apunta a un objeto diferente de array1, pero sus elementos apuntan a los mismos objetos que en array1. Maraycopy 1 también puede modificar sus propios objetos.
[marray copy 1 add object: @"de"];
[marray copy 1 removeObjectAtIndex: 0]
Array1 y arrayCopy1 son copias de puntero, Si bien MaryCopy 1 es una copia de objeto, MaryCopy 1 también puede cambiar elementos en un punto: eliminar o agregar. Pero tenga en cuenta que el contenido de los elementos del contenedor son copias de puntero.
Probemos con otro ejemplo.
NSArray * marray 1 = [NSArray arrayWithObjects: [NSMutableString cadena con cadena: @"a"], @"b", @"c", nil];
NSArray * marray copia 2 = [matrimonio 1 copia];
NSLog (@"mArray1 retiene el recuento: d", [matrimonio 1 retiene el recuento]); copia mutable】;
NSLog(@"recuento de retención de mArray1: d", [recuento de retención de matrimonio 1]);
//ArrayCopy2, MarryMcCoy1 y Marry1 apuntan a objetos diferentes, Pero los elementos que contiene son el mismo objeto: el mismo puntero.
//Haz una prueba.
NSMutableString * testString = [marray 1 objectAtIndex: 0];
// testString = @"1a 1" // Esto cambiará el puntero de testString y realmente cambiará @"; 1a 1 "Objeto temporal asignado a testString.
[testString appendString: @"tail"]; // De esta manera, se cambia el primer elemento de las tres matrices anteriores.
Por lo tanto, para un contenedor, sus objetos elemento siempre son copias de puntero. Si también necesita copiar objetos de elementos, debe implementar una copia profunda. /library/MAC/#documentation/Cocoa/Conceptual/Collections/Articles/copying .html
NSArray * array = [NSArray arrayWithObjects: [NSMutableString string withstring: @"first"], [NSStringstringWithString: @" b"], @"c", nil];
NSArray * deepcopyray = [[NSArray alloc] init con matriz: elementos de copia de matriz: YES];
NSArray * truedepcopyarray = [nskeydunarchiver unarchiveObjectWithData:
[nskeydarchiver archivedDataWithRootObject:array]];
TrueDeepCopyArray es una copia profunda completa, pero DeepCopyArray no lo es. Para elementos inmutables en deepCopyArray, sigue siendo una copia de puntero. O podemos implementar una copia profunda nosotros mismos. Porque si un elemento de un contenedor es inmutable, el objeto no se puede cambiar después de copiarlo, por lo que simplemente lo copia con un puntero. A menos que reasigne los elementos en el contenedor, una copia del puntero es suficiente. Por ejemplo, después de [[ArrayObjectIndex: 0]AppendString: @"SD"], otros objetos en el contenedor no se verán afectados.
[[ArrayObjectIndex: 1] y [[Deepcopy ArrayObjectIndex: 0] apuntan a la misma memoria, pero no podemos modificarla, porque es inmutable. Entonces copiar el puntero es suficiente. Así que esta no es exactamente una copia profunda, pero la documentación oficial de Apple la enumera como una copia profunda y agrega una descripción de la relación entre copia y mutabilidad, así que lo explicaré aquí.