Digamos que tengo una clase llamada SomeClass
con un string
nombre de propiedad:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
Entiendo que se le puede asignar un nombre, NSMutableString
en cuyo caso esto puede conducir a un comportamiento erróneo.
- Para las cadenas en general, ¿es siempre una buena idea usar el
copy
atributo en lugar deretain
? - ¿Es una propiedad "copiada" de alguna manera menos eficiente que una propiedad "retenida"?
objective-c
cocoa
cocoa-touch
Martillo de peste
fuente
fuente
name
debe publicardealloc
o no?Respuestas:
Para los atributos cuyo tipo es una clase de valor inmutable que se ajusta al
NSCopying
protocolo, casi siempre debe especificarcopy
en su@property
declaración. Especificarretain
es algo que casi nunca quieres en una situación así.He aquí por qué quieres hacer eso:
El valor actual de la
Person.name
propiedad será diferente dependiendo de si la propiedad está declaradaretain
ocopy
, lo será@"Debajit"
si está marcadaretain
, pero@"Chris"
si está marcadacopy
.Dado que en casi todos los casos desea evitar la mutación de los atributos de un objeto a sus espaldas, debe marcar las propiedades que los representan
copy
. (Y si escribe el setter usted mismo en lugar de usarlo@synthesize
, recuerde usarlo encopy
lugar de usarloretain
).fuente
NSMutableString
, excepto como un tipo de "generador de cadenas" transitorio (del cual tomo inmediatamente una copia inmutable). Preferiría que fueran tipos discretos, pero permitiré que el hecho de que la copia sea libre de retener si la cadena original no es mutable mitiga la mayor parte de mi preocupación.La copia debe usarse para NSString. Si es mutable, entonces se copia. Si no es así, simplemente se retiene. Exactamente la semántica que desea en una aplicación (deje que el tipo haga lo mejor).
fuente
NSString
propiedad declarada comocopy
se obtendrá deretain
todos modos (si es inmutable, por supuesto). Otro ejemplo que se me ocurre esNSNumber
.Sí, en general siempre use el atributo de copia.
Esto se debe a que su propiedad NSString puede pasar una instancia de NSString o una instancia de NSMutableString y, por lo tanto, no podemos determinar realmente si el valor que se pasa es un objeto inmutable o mutable.
Si su propiedad pasa una instancia de NSString , la respuesta es " No ": la copia no es menos eficiente que la retención.
(No es menos eficiente porque NSString es lo suficientemente inteligente como para no realizar una copia).
Si su propiedad pasa una instancia de NSMutableString , la respuesta es " Sí ": la copia es menos eficiente que la retención.
(Es menos eficiente porque debe ocurrir una asignación de memoria real y una copia, pero esto es probablemente algo deseable).
En términos generales, una propiedad "copiada" tiene el potencial de ser menos eficiente; sin embargo, mediante el uso del
NSCopying
protocolo, es posible implementar una clase que es "tan eficiente" para copiar como para retener. Las instancias de NSString son un ejemplo de esto.Siempre debe usarlo
copy
cuando no desee que el estado interno de la propiedad cambie sin previo aviso. Incluso para objetos inmutables: los objetos inmutables escritos correctamente manejarán la copia de manera eficiente (consulte la siguiente sección sobre inmutabilidad yNSCopying
).Puede haber razones de rendimiento para los
retain
objetos, pero viene con una sobrecarga de mantenimiento: debe administrar la posibilidad de que el estado interno cambie fuera de su código. Como dicen, optimice al final.Sin uso
copy
. Si su clase es realmente inmutable, entonces es una buena práctica implementar elNSCopying
protocolo para que su clase regrese cuandocopy
se use. Si haces esto:copy
.copy
anotación hace que su propio código sea máscopy
fácil de mantener; la anotación indica que realmente no necesita preocuparse por si este objeto cambia de estado en otro lugar.fuente
Intento seguir esta simple regla:
¿Quiero conservar el valor del objeto en el momento en que lo asigno a mi propiedad? Uso de la copia .
¿Quiero aferrarme al objeto y no me importa cuáles son sus valores internos actualmente o serán en el futuro? Use fuerte (retener).
Para ilustrar: ¿Quiero aferrarme al nombre "Lisa Miller" ( copia ) o quiero aferrarme a la persona Lisa Miller ( fuerte )? Su nombre podría cambiar luego a "Lisa Smith", pero seguirá siendo la misma persona.
fuente
A través de este ejemplo, copiar y retener se puede explicar como:
si la propiedad es de tipo copia entonces,
Se creará una nueva copia para la
[Person name]
cadena que contendrá el contenido de lasomeName
cadena. Ahora cualquier operación ensomeName
cadena no tendrá efecto[Person name]
.[Person name]
y lassomeName
cadenas tendrán diferentes direcciones de memoria.Pero en caso de retener,
ambos
[Person name]
contendrán la misma dirección de memoria que la cadena de nombre, solo el recuento retenido de la cadena de nombre se incrementará en 1.Por lo tanto, cualquier cambio en la cadena de nombre se reflejará en la
[Person name]
cadena.fuente
Seguramente, poner 'copia' en una declaración de propiedad se opone al uso de un entorno orientado a objetos donde los objetos en el montón se pasan 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 el valor de una propiedad debe 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:
Por supuesto, al diseñar el objeto que contiene esa propiedad, solo usted sabrá si el diseño se beneficia de un patrón donde las tareas toman copias: Cocoawithlove.com tiene lo siguiente que decir:
"Debe usar un descriptor de acceso de copia cuando el parámetro setter puede ser mutable pero no puede cambiar el estado interno de una propiedad sin previo aviso ", por lo que la decisión de si puede soportar el valor de cambiar inesperadamente es suya. Imagina este escenario:
En este caso, sin usar la copia, nuestro objeto de contacto toma el nuevo valor automáticamente; si lo usáramos, sin embargo, tendríamos que asegurarnos manualmente de que los cambios fueron detectados y sincronizados. En este caso, retener la semántica puede ser deseable; en otro, la copia podría ser más apropiada.
fuente
fuente
Debe usar la copia todo el tiempo para declarar la propiedad NSString
Debe leerlos para obtener más información sobre si devuelve una cadena inmutable (en caso de que se haya pasado una cadena mutable) o si devuelve una cadena retenida (en caso de que se haya pasado una cadena inmutable)
Referencia de protocolo de copia NS
Objetos de valor
fuente
Como el nombre es un (inmutable)
NSString
, copiar o retener no hace ninguna diferencia si configura otroNSString
nombre. En otras palabras, copiar se comporta como retener, aumentando el recuento de referencias en uno. Creo que es una optimización automática para clases inmutables, ya que son inmutables y no necesitan ser clonadas. Pero cuandoNSMutalbeString
mstr
se establece un nombre, el contenido demstr
se copiará en aras de la corrección.fuente
Si la cadena es muy grande, la copia afectará el rendimiento y dos copias de la cadena grande usarán más memoria.
fuente