framework español objective-c cocoa cocoa-touch

objective c - español - Propiedad NSString: copiar o retener?



cocoa touch español (10)

Para las cadenas en general, ¿es siempre una buena idea usar el atributo de copia en lugar de retener?

Sí, en general siempre use el atributo de copia.

Esto se debe a que a su propiedad NSString se le puede pasar una instancia NSString o una instancia NSMutableString y, por lo tanto, no podemos determinar realmente si el valor que se pasa es un objeto inmutable o mutable.

¿Es una propiedad "copiada" de alguna manera menos eficiente que dicha propiedad "retenida"?

  • Si a su propiedad se le pasa una instancia de NSString , la respuesta es " No ": la copia no es menos eficiente que retener.
    (No es menos eficiente porque el NSString es lo suficientemente inteligente como para no realizar una copia).

  • Si su propiedad recibe una instancia de NSMutableString , la respuesta es " ": la copia es menos eficiente que la retención.
    (Es menos eficiente porque debe haber una asignación de memoria real y una copia, pero esto probablemente sea algo deseable).

  • En términos generales, una propiedad "copiada" tiene el potencial de ser menos eficiente; sin embargo, a través del uso del protocolo NSCopying , es posible implementar una clase que sea "tan eficiente" para copiar como para conservar. Las instancias de NSString son un ejemplo de esto.

En general (no solo para NSString), ¿cuándo debo usar "copiar" en lugar de "retener"?

Siempre debe usar la copy cuando no desee que el estado interno de la propiedad cambie sin previo aviso. Incluso para objetos inmutables: los objetos inmutables correctamente escritos manejarán la copia de manera eficiente (consulte la siguiente sección sobre inmutabilidad y NSCopying ).

Puede haber motivos de rendimiento para retain objetos, pero conlleva una sobrecarga de mantenimiento: debe administrar la posibilidad de que el estado interno cambie fuera de su código. Como se suele decir, optimizar al final.

Pero, escribí mi clase para ser inmutable, ¿no puedo simplemente "retenerla"?

No - utilizar copy . Si su clase es realmente inmutable, entonces es una buena práctica implementar el protocolo NSCopying para que su clase se devuelva a sí misma cuando se utiliza la copy . Si haces esto:

  • Otros usuarios de su clase obtendrán los beneficios de rendimiento cuando utilicen la copy .
  • La anotación de copy hace que su propio código sea más fácil de mantener; la anotación de copy indica que realmente no necesita preocuparse por el cambio de estado de este objeto en otro lugar.

Digamos que tengo una clase llamada SomeClass con un nombre de propiedad de string :

@interface SomeClass : NSObject { NSString* name; } @property (nonatomic, retain) NSString* name; @end

Entiendo que a ese nombre se le puede asignar una NSMutableString en cuyo caso esto puede llevar a un comportamiento errante.

  • Para las cadenas en general, ¿es siempre una buena idea usar el atributo de copy lugar de retain ?
  • ¿Es una propiedad "copiada" de alguna manera menos eficiente que dicha propiedad "retenida"?

A través de este ejemplo se puede explicar copiar y retener como:

NSMutableString *someName = [NSMutableString stringWithString:@"Chris"]; Person *p = [[[Person alloc] init] autorelease]; p.name = someName; [someName setString:@"Debajit"];

Si la propiedad es de tipo copia entonces,

se creará una nueva copia para la cadena [Person name] que contendrá el contenido de la cadena de someName . Ahora, cualquier operación en la cadena de algún someName no tendrá efecto en [Person name] .

[Person name] y someName cadenas de algún nombre tendrán diferentes direcciones de memoria.

Pero en caso de retener,

tanto el [Person name] tendrá la misma dirección de memoria como de la cadena somename, solo el número retenido de la cadena somename se incrementará en 1.

Por lo tanto, cualquier cambio en la cadena somename se reflejará en la cadena [Person name] .


Dado que el nombre es un NSString (inmutable), copiar o retener no hace ninguna diferencia si establece otro NSString en el nombre. En otra palabra, la copia se comporta igual que retener, aumentando la cuenta de referencia en uno. Creo que es una optimización automática para clases inmutables, ya que son inmutables y no necesitan ser clonadas. Pero cuando un NSMutalbeString mstr se establece en nombre, el contenido de mstr se copiará por el bien de la corrección.


Debe usar copiar todo el tiempo para declarar la propiedad NSString

@property (nonatomic, copy) NSString* name;

Debe leer estos para obtener más información sobre si devuelve una cadena inmutable (en caso de que se haya pasado una cadena mutable) o una cadena retenida (en caso de que se haya pasado una cadena inmutable)

Referencia del protocolo NSCopying

Implemente NSCopying conservando el original en lugar de crear una nueva copia cuando la clase y su contenido sean inmutables

Objetos de valor

Entonces, para nuestra versión inmutable, podemos hacer esto:

- (id)copyWithZone:(NSZone *)zone { return self; }


Intento seguir esta simple regla:

  • ¿Deseo conservar el valor del objeto en el momento en el que lo estoy asignando a mi propiedad? Utilizar copia .

  • ¿Quiero aferrarme al objeto y no me importa cuáles son sus valores internos actualmente o cuáles serán en el futuro? Utilice fuerte (retener).

Para ilustrar: ¿Quiero aferrarme al nombre "Lisa Miller" ( copiar ) o a la persona Lisa Miller ( fuerte )? Su nombre podría cambiar más tarde a "Lisa Smith", pero seguirá siendo la misma persona.


Para los atributos cuyo tipo es una clase de valor inmutable que se ajusta al protocolo NSCopying , casi siempre debe especificar una copy en su declaración de @property . Especificar retain es algo que casi nunca quiere en una situación así.

Aquí es por qué quieres hacer eso:

NSMutableString *someName = [NSMutableString stringWithString:@"Chris"]; Person *p = [[[Person alloc] init] autorelease]; p.name = someName; [someName setString:@"Debajit"];

El valor actual de la propiedad Person.name será diferente dependiendo de si la propiedad se declara retain o copy : será @"Debajit" si la propiedad está marcada como @"Debajit" , pero @"Chris" si la propiedad está marcada como copy .

Dado que en casi todos los casos desea evitar mutar los atributos de un objeto detrás de su parte posterior, debe marcar las propiedades que representan su copy . (Y si usted mismo escribe el setter en lugar de usar @synthesize , debería recordar usar la copy lugar de retain ).


Seguramente, poner ''copia'' en una declaración de propiedad se compara con el uso de un entorno orientado a objetos donde se pasan los objetos en el montón por referencia: uno de los beneficios que obtiene aquí es que, al cambiar un objeto, todas las referencias a ese objeto. Ver los últimos cambios. Muchos idiomas proporcionan ''ref'' o palabras clave similares para permitir que los tipos de valor (es decir, estructuras en la pila) se beneficien del mismo comportamiento. Personalmente, usaría la copia con moderación, y si considerara que un valor de propiedad debería protegerse de los cambios realizados en el objeto desde el que fue asignado, podría llamar al método de copia de ese objeto durante la asignación, por ejemplo:

p.name = [someName copy];

Por supuesto, al diseñar el objeto que contiene esa propiedad, solo usted sabrá si el diseño se beneficia de un patrón en el que las asignaciones toman copias: Cocoawithlove.com tiene lo siguiente que decir:

"Debe usar un dispositivo de acceso a la copia cuando el parámetro de establecimiento puede ser modificable, pero no puede cambiar el estado interno de una propiedad sin avisar ", por lo que la decisión de si puede soportar el valor para cambiar de forma inesperada es suya. Imagina este escenario:

//person object has details of an individual you''re assigning to a contact list. Contact *contact = [[[Contact alloc] init] autorelease]; contact.name = person.name; //person changes name [[person name] setString:@"new name"]; //now both person.name and contact.name are in sync.

En este caso, sin usar copia, nuestro objeto de contacto toma el nuevo valor automáticamente; Sin embargo, si lo usáramos, tendríamos que asegurarnos manualmente de que los cambios se detectaron y sincronizaron. En este caso, retener la semántica podría ser deseable; en otro, copiar podría ser más apropiado.


Si la cadena es muy grande, la copia afectará el rendimiento y dos copias de la cadena grande usarán más memoria.


Copia debe utilizarse para NSString. Si es Mutable, entonces se copia. Si no lo es, entonces se retiene. Exactamente la semántica que desea en una aplicación (deje que el tipo haga lo que sea mejor).


@interface TTItem : NSObject @property (nonatomic, copy) NSString *name; @end { TTItem *item = [[TTItem alloc] init]; NSString *test1 = [NSString stringWithFormat:@"%d / %@", 1, @"Go go go"]; item.name = test1; NSLog(@"-item.name: point = %p, content = %@; test1 = %p", item.name, item.name, test1); test1 = [NSString stringWithFormat:@"%d / %@", 2, @"Back back back"]; NSLog(@"+item.name: point = %p, content = %@, test1 = %p", item.name, item.name, test1); } Log: -item.name: point = 0x9a805a0, content = 1 / Go go go; test1 = 0x9a805a0 +item.name: point = 0x9a805a0, content = 1 / Go go go, test1 = 0x9a84660