@property retención, asignación, copia, no atómico en Objective-C

214

Como alguien nuevo en Objective-C, ¿alguien puede darme una visión general de la retención, asignación, copia y cualquier otra que me falte, que siga la directiva @property? ¿Qué están haciendo y por qué querría usar uno sobre otro?

Mark Reid
fuente
1
El nombre de Apple para estos es "atributos" o "atributos de propiedad"
nevan king

Respuestas:

273

El artículo vinculado a MrMage ya no funciona. Entonces, esto es lo que aprendí en mi (muy) breve codificación en Objective-C:

no atómico frente a atómico: "atómico" es el valor predeterminado. Utilice siempre "no atómico". No sé por qué, pero el libro que leí decía que "rara vez hay una razón" para usar "atómico". (Por cierto: el libro que leí es el libro "Programación iOS" de BNR).

readwrite vs. readonly - "readwrite" es el valor predeterminado. Cuando se sintetiza, se crearán un getter y un setter para usted. Si usa "solo lectura", no se creará ningún setter. Úselo para un valor que no quiera cambiar después de la instanciación del objeto.

retener vs. copiar vs. asignar

  • "asignar" es el valor predeterminado. En el setter creado por @synthesize, el valor simplemente se asignará al atributo. Tengo entendido que "asignar" se debe utilizar para los atributos sin puntero.
  • "Retener" es necesario cuando el atributo es un puntero a un objeto. El setter generado por @synthesize retendrá (también conocido como un recuento de retención) el objeto. Deberá liberar el objeto cuando haya terminado con él.
  • Se necesita "copiar" cuando el objeto es mutable. Use esto si necesita el valor del objeto tal como está en este momento, y no desea que ese valor refleje los cambios realizados por otros propietarios del objeto. Deberá liberar el objeto cuando haya terminado con él porque está reteniendo la copia.
Blamdarot
fuente
@Blamdarot - ¿Necesito lanzarlo también con ARC?
Dejell
10
@Odelya - No. Si liberas mientras usas ARC, creo que obtendrás un error de compilación.
Blamdarot
52
"Usar siempre no atómico" es un mal consejo. Debes saber a qué estás renunciando cuando usas nonatomic.
Jesse Rusak
77
Convenido. En particular, muchas personas no parecen saber que los valores no atómicos no son retenidos automáticamente por el captador. a menudo no atómico es apropiado, pero la programación de culto de carga rara vez lo es.
Catfish_Man
99
Aconsejar dejar el valor predeterminado atomices tan malo como aconsejar nonatomic. Ninguna de las opciones es la "correcta", por lo que los diseñadores de idiomas optaron por la más segura de las dos soluciones. De hecho, nonatomicgeneralmente es la mejor opción, ya que omite bloqueos de rosca extremadamente caros. La única razón para usar atomices si su propiedad puede establecerse desde varios subprocesos (en cuyo caso, omitirla puede provocar una liberación excesiva o una fuga).
Adam Kaplan
295

Antes de conocer los atributos de @property, debe saber para qué sirve @property.

  • @property ofrece una forma de definir la información que una clase pretende encapsular. Si declara un objeto / variable usando @property , entonces ese objeto / variable será accesible para otras clases que importen su clase.

  • Si declara un objeto usando @property en el archivo de encabezado, debe sintetizarlo usando @synthesize en el archivo de implementación. Esto hace que el objeto sea compatible con KVC . Por defecto, el compilador sintetizará métodos de acceso para este objeto.

  • Los métodos de acceso son: setter y getter.

Ejemplo: .h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.metro

@implementation XYZClass
@synthesize name;
@end

Ahora el compilador sintetizará métodos de acceso para el nombre .

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • Lista de atributos de @property

    atómico, no atómico, retener, copiar, solo lectura, reescribir, asignar, fuerte, getter = método, setter = método, inseguro_retenido

  • atómico es el comportamiento predeterminado. Si un objeto se declara como atómico, se vuelve seguro para subprocesos. Seguridad para subprocesos significa que, en un momento, solo un subproceso de una instancia particular de esa clase puede tener el control sobre ese objeto.

Si el hilo realiza el método getter, entonces otro hilo no puede realizar el método setter en ese objeto. Es lento.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • no atómico no es seguro para subprocesos. Puede usar el atributo de propiedad no atómica para especificar que los accesos sintetizados simplemente establecen o devuelven un valor directamente, sin garantías sobre lo que sucede si se accede al mismo valor simultáneamente desde diferentes subprocesos.

Por esta razón, es más rápido acceder a una propiedad no atómica que a una atómica.

@property (nonatomic)NSString *name;   
  • se requiere retener cuando el atributo es un puntero a un objeto.

El método de establecimiento aumentará el recuento de retención del objeto, de modo que ocupará memoria en el grupo de liberación automática.

@property (retain)NSString *name;
  • copy Si usa copy, no puede usar retener. El uso de la instancia de copia de la clase contendrá su propia copia.

Incluso si se establece una cadena mutable y luego se cambia, la instancia captura cualquier valor que tenga en el momento en que se establece. No se sintetizarán métodos setter y getter.

@property (copy) NSString *name;

ahora,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

el nombre no se verá afectado.

  • solo lectura Si no desea permitir que la propiedad se cambie mediante el método setter, puede declarar la propiedad solo lectura.

El compilador generará un getter, pero no un setter.

@property (readonly) NSString *name;
  • readwrite es el comportamiento predeterminado. No necesita especificar el atributo readwrite explícitamente.

Es lo contrario de solo lectura.

@property (readwrite) NSString *name;
  • asignar generará un setter que asigna el valor a la variable de instancia directamente, en lugar de copiarlo o retenerlo. Esto es mejor para tipos primitivos como NSInteger y CGFloat, u objetos que no son de su propiedad, como los delegados.

Tenga en cuenta que retener y asignar son básicamente intercambiables cuando la recolección de basura está habilitada.

@property (assign) NSInteger year;
  • fuerte es un reemplazo para retener.

Viene con ARC.

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method Si desea usar un nombre diferente para un método getter, es posible especificar un nombre personalizado agregando atributos a la propiedad.

En el caso de las propiedades booleanas (propiedades que tienen un valor SÍ o NO), es habitual que el método getter comience con la palabra "es"

@property (getter=isFinished) BOOL finished;
  • setter = method Si desea usar un nombre diferente para un método setter, es posible especificar un nombre personalizado agregando atributos a la propiedad.

El método debe terminar con dos puntos.

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained Hay algunas clases en Cocoa y Cocoa Touch que aún no admiten referencias débiles, lo que significa que no puede declarar una propiedad débil o una variable local débil para realizar un seguimiento de ellas. Estas clases incluyen NSTextView, NSFont y NSColorSpace, etc. Si necesita usar una referencia débil a una de estas clases, debe usar una referencia insegura.

Una referencia insegura es similar a una referencia débil ya que no mantiene vivo su objeto relacionado, pero no se establecerá en nulo si el objeto de destino se desasigna.

@property (unsafe_unretained) NSObject *unsafeProperty;

Si necesita especificar varios atributos, simplemente inclúyalos como una lista separada por comas, como esta:

@property (readonly, getter=isFinished) BOOL finished;
liza
fuente
Además, débil significa que no hay un recuento de referencia al objeto al que se hace referencia, sino que se hace referencia en absoluto o no se hace referencia en absoluto. Algo así como "sí, algo me hizo referencia" frente a "existen 9 referencias a mí" (que es lo que es fuerte).
Alex Zavatone
66
Ignore la línea en la respuesta con respecto a la recolección de basura, ya que la recolección de basura está en desuso en Mac OS X y no existe en iOS según la documentación de Apple .
Basil Bourque
44
"Nota: la atomicidad de la propiedad no es sinónimo de la seguridad del hilo de un objeto". - de developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7
1
"Si declaras un objeto usando @propertyen el archivo de encabezado, entonces tienes que sintetizarlo usando@synthesize en el archivo de implementación." No siempre. Por ejemplo, "Por defecto, una readwritepropiedad estará respaldada por una variable de instancia, que nuevamente será sintetizada automáticamente por el compilador". De doc .
Franklin Yu
44
@liza Esta es una excelente respuesta. ¿Por qué esta no es la respuesta aceptada? Transmite una explicación mucho más eficiente que la respuesta actualmente aceptada. A veces no entiendo StackOverflow?
Charles Robertson el
149

Después de leer muchos artículos, decidí reunir toda la información de los atributos:

  1. atómico // predeterminado
  2. no atómico
  3. fuerte = retener // predeterminado
  4. débil = inseguro_reretenido
  5. conservar
  6. asignar // predeterminado
  7. inseguro_reretenido
  8. Copiar
  9. solo lectura
  10. readwrite // predeterminado

A continuación hay un enlace al artículo detallado donde puede encontrar estos atributos.

¡Muchas gracias a todas las personas que dan las mejores respuestas aquí!

Atributos de propiedad variable o modificadores en iOS

Aquí está la descripción de muestra del artículo

  1. atómico -Atomic significa que solo un hilo accede a la variable (tipo estático). -Atomic es seguro para hilos. -pero es lento en rendimiento -atómico es el comportamiento predeterminado -Accesores atómicos en un entorno no recolectado (es decir, cuando se usa retención / liberación / liberación automática) usarán un bloqueo para garantizar que otro hilo no interfiera con la configuración / obtención correcta del valor -no es en realidad una palabra clave.

Ejemplo:

@property (retain) NSString *name;

@synthesize name;
  1. nonatomic -Natatomic significa acceso múltiple a la variable (tipo dinámico). -Natatomic es hilo inseguro. -pero es rápido en rendimiento -No atómico NO es un comportamiento predeterminado, necesitamos agregar una palabra clave no atómica en el atributo de propiedad. -puede provocar un comportamiento inesperado, cuando dos procesos diferentes (hilos) acceden a la misma variable al mismo tiempo.

Ejemplo:

@property (nonatomic, retain) NSString *name;

@synthesize name;

Explique:

Suponga que hay una propiedad de cadena atómica llamada "nombre", y si llama a [self setName: @ "A"] desde el hilo A, llame a [self setName: @ "B"] desde el hilo B y llame a [self name] desde subproceso C, todas las operaciones en subprocesos diferentes se realizarán en serie, lo que significa que si un subproceso está ejecutando setter o getter, otros subprocesos esperarán. Esto hace que la propiedad "nombre" lea / escriba de manera segura, pero si otro hilo D llama [liberación de nombre] simultáneamente, esta operación podría producir un bloqueo porque no hay una llamada de establecimiento / obtención involucrada aquí. Lo que significa que un objeto es seguro para lectura / escritura (ATOMIC) pero no para subprocesos, ya que otros subprocesos pueden enviar simultáneamente cualquier tipo de mensajes al objeto. El desarrollador debe garantizar la seguridad del hilo para dichos objetos.

Si la propiedad "nombre" no era atómica, entonces todos los hilos en el ejemplo anterior - A, B, C y D se ejecutarán simultáneamente produciendo cualquier resultado impredecible. En el caso de atómico, cualquiera de A, B o C se ejecutará primero pero D aún puede ejecutarse en paralelo.

  1. fuerte (iOS4 = retener) -dice "mantener esto en el montón hasta que ya no lo señale" -en otras palabras "Soy el propietario, no puedes tratar esto antes de apuntar bien con lo mismo que retener" - Usas fuerte solo si necesitas retener el objeto. -Por defecto, todas las variables de instancia y las variables locales son punteros fuertes. -Generalmente usamos fuerte para UIViewControllers (padres del elemento de IU) -fuerte se usa con ARC y básicamente te ayuda, al no tener que preocuparte por el conteo de retención de un objeto. ARC lo libera automáticamente cuando haya terminado. Usar la palabra clave strong significa que usted es el propietario del objeto.

Ejemplo:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
  1. débil (iOS4 = unsafe_unretained) -dice "mantener esto siempre y cuando alguien más lo señale con fuerza" -lo mismo que asignar, no retener o liberar -Una referencia "débil" es una referencia que no retiene. -Generalmente usamos débil para IBOutlets (UIViewController's Childs). Esto funciona porque el objeto hijo solo necesita existir mientras el objeto padre lo haga. -una referencia débil es una referencia que no protege el objeto referenciado de la recolección por un recolector de basura. -Debil es esencialmente asignar, una propiedad no retenida. Excepto cuando el objeto se desasigna, el puntero débil se establece automáticamente en cero

Ejemplo:

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Explicación fuerte y débil, gracias a BJ Homer :

Imagine que nuestro objeto es un perro, y que el perro quiere huir (ser desasignado). Punteros fuertes son como una correa en el perro. Mientras tenga la correa atada al perro, el perro no huirá. Si cinco personas atan su correa a un perro (cinco punteros fuertes a un objeto), entonces el perro no se escapará hasta que se quiten las cinco correas. Los indicadores débiles, por otro lado, son como niños pequeños apuntando al perro y diciendo "¡Mira! ¡Un perro!" Mientras el perro todavía esté con la correa, los niños pequeños aún pueden ver al perro y aún lo señalarán. Sin embargo, tan pronto como se sueltan todas las correas, el perro se escapa sin importar cuántos niños pequeños lo señalen. Tan pronto como el último puntero fuerte (correa) ya no apunte a un objeto, el objeto se desasignará y todos los punteros débiles se pondrán a cero. Cuando usamos débil? El único momento en que desearía usar débil, es si desea evitar retener ciclos (por ejemplo, el padre retiene al niño y el niño retiene al padre para que ninguno sea liberado).

  1. retener = fuerte -se retiene, el valor anterior se libera y se asigna -retener especifica que se debe enviar el nuevo valor -retener en la asignación y el valor anterior enviado -release -retain es lo mismo que fuerte. -apple dice que si escribe retener, se convertirá automáticamente / funcionará solo como fuerte. -métodos como "alloc" incluyen un "retener" implícito

Ejemplo:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. asignar -assign es el valor predeterminado y simplemente realiza una asignación variable -assign es un atributo de propiedad que le dice al compilador cómo sintetizar la implementación del establecedor de la propiedad -Utilizaría asignar para propiedades primitivas C y débil para referencias débiles a objetos Objective-C.

Ejemplo:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. inseguro_reretenido

    -unsafe_unretained es un calificador de propiedad que le dice a ARC cómo insertar llamadas retener / liberar -unsafe_unretained es la versión ARC de asignar.

Ejemplo:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. se requiere copia-copia cuando el objeto es mutable. -copy especifica que el nuevo valor debe enviarse -copy en la asignación y el antiguo valor enviado -release. -copy es como retener devuelve un objeto que debe liberar explícitamente (por ejemplo, en dealloc) en entornos no recolectados de basura. -si usa copy, aún necesita liberar eso en dealloc. -Utilice esto si necesita el valor del objeto tal como está en este momento, y no desea que ese valor refleje los cambios realizados por otros propietarios del objeto. Deberá liberar el objeto cuando haya terminado con él porque está reteniendo la copia.

Ejemplo:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;
swiftBoy
fuente
2
Creo que después del arco, retener ya no se usa.
Mert
1
la lista completa pierde 2 elementos de opción: setter y getter, que también son las únicas opciones que necesitan argumento.
Scott Chu
fuerte o retener es predeterminado para el tipo de objeto solamente. No se puede usar para tipos primitivos.
Saleh Enam Shohag
9

Solo se puede acceder a la propiedad atómica a la vez. Es seguro para hilos . El valor predeterminado es atómico. Tenga en cuenta que no hay una palabra clave atómica

No atómico significa que varios subprocesos pueden acceder al elemento. No es seguro

Por lo tanto, debe tener mucho cuidado al usar atomic. Como afecta el rendimiento de su código

Kannan Prasad
fuente
3
"Nota: la atomicidad de la propiedad no es sinónimo de la seguridad del hilo de un objeto". de developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7