Objetivo-C ARC: fuerte vs retener y débil vs asignar

367

Hay dos nuevos atributos de administración de memoria para las propiedades introducidas por ARC, strongy weak.

Aparte de copy, que obviamente es algo completamente diferente, ¿hay alguna diferencia entre strongvs retainy weakvs assign?

Según tengo entendido, la única diferencia aquí es que weakse asignará nilal puntero, mientras assignque no lo hará, lo que significa que el programa se bloqueará cuando envíe un mensaje al puntero una vez que se haya lanzado. Pero si lo uso weak, esto nunca sucederá, porque el mensaje enviado a nilno hará nada.

No sé acerca de las diferencias entre strongy retain.

¿Hay alguna razón por la que debería usar assigny retainen nuevos proyectos, o están siendo desaprobados?

Jakub Arnold
fuente
12
Hay tres nuevos atributos de administración de memoria para las propiedades introducidas por ARC strong, weaky unsafe_unretained.
NJones
55
@NJones Hay dos atributos de propiedad ( weaky strong) y 4 calificadores de toda la vida variables ( __strong, __weak, __unsafe_unretained, __autoreleasing). Vea las notas de ARC a continuación.
Snowcrash
1
@SnowCrash Hubo una versión de Xcode, probablemente una vista previa del desarrollador, en la que usar assignal compilar con ARC fue un error. Hay muchas respuestas eliminadas sobre esto. Parece que fue cambiado antes del lanzamiento final. unsafe_unretainedes el atributo preferido para muchos de los primeros en adoptar. Para comprobar que unsafe_unretainedes un atributo válido, consulte "Programación con Objective-C" de Apple en la sección "Datos encapsulados" bajo el subtítulo "Usar referencias no retenidas inseguras para algunas clases". Que dice: "Para una propiedad, esto significa usar el atributo unsafe_unretained:"
NJones

Respuestas:

230

Desde la transición a las notas de la versión ARC (el ejemplo en la sección sobre atributos de propiedad).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

Entonces stronges lo mismo que retainen una declaración de propiedad.

Para proyectos ARC que usaría en stronglugar de retain, usaría assignpara propiedades primitivas C y weakpara referencias débiles a objetos Objective-C.

JeremyP
fuente
11
De hecho, bajo ARC es un error de compilación assignpara un objeto. Debe usar uno weako unsafe_unretained(lo cual no es seguro, obviamente) si no desea conservar la propiedad.
cobbal
55
assigncompila muy bien para mí en proyectos ARC con destino de implementación 4.0.
Pascal
8
@Pascal: no se permiten referencias débiles en los objetivos de implementación donde el sistema operativo no es 5.0 o superior. Por lo tanto, para proyectos más antiguos todavía puede usar asignar, pero si cambia a versiones más nuevas, debe cambiar a débil
Mattia,
1
Se parece a Xcode 4 (ARC) genera NSManagedObject subclases utilizando retainvs strong. Supongo que es en su mayoría inofensivo, pero imagino que debería ser strongpor consistencia ... o tal vez no importa. stackoverflow.com/questions/7796476/…
Joe D'Andrea
3
@ JeremyP Sí, su respuesta es acertada. Estaba reaccionando a @Mattia. Estaba señalando que assigntodavía es válido en algunos casos.
Steven Oxley
606

Después de leer tantos artículos, publicaciones de Stackoverflow y aplicaciones de demostración para verificar los atributos de las propiedades variables, decidí reunir toda la información de los atributos:

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

A continuación se muestra el enlace detallado del artículo donde puede encontrar todos los atributos mencionados anteriormente, que definitivamente lo ayudarán. ¡Muchas gracias a todas las personas que dan las mejores respuestas aquí!

Atributos de propiedad variable o modificadores en iOS

1.fuerte (iOS4 = retener)

  • dice "mantén 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.
  • Por lo general, utilizamos fuerte para UIViewControllers (elementos del elemento de la interfaz de usuario)
  • strong 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 con él. Usar la palabra clave strong significa que usted es el propietario del objeto.

Ejemplo:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2.weak -

  • dice "mantén esto siempre que alguien más lo señale fuertemente"
  • lo mismo que asignar, no retener o liberar
  • Una referencia "débil" es una referencia que no retiene.
  • Generalmente usamos débil para IBOutlets (Childs de UIViewController's). 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 parte de un recolector de basura.
  • Débil 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 :

Imagina que nuestro objeto es un perro y que el perro quiere escapar (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 huirá hasta que las cinco correas se separen.

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 será desasignado 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).

3.retener = fuerte

  • se retiene, se libera el valor anterior y se le asigna la retención especifica que se debe enviar el nuevo valor
  • retener en la asignación y el valor anterior enviado - liberación
  • retener 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;

4.asignar

  • asignar es el valor predeterminado y simplemente realiza una asignación variable
  • asignar es un atributo de propiedad que le dice al compilador cómo sintetizar la implementación del establecedor de la propiedad
  • Usarí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;
swiftBoy
fuente
55
2. "una referencia débil es una referencia que no protege el objeto referenciado de la recolección por parte de un recolector de basura" - no existe tal cosa en el objetivo c como recolector de basura;
Bucherland
1
y esta jerarquía es administrada por iOS automáticamente. Lea sobre el concepto MVC. Quiero decir que cuando se presenta ViewContorller, iOS carga su jerarquía de vistas en la pantalla (creando vistas faltantes). Cuando se presenta otro ViewController, esta primera jerarquía de vistas se desasigna. Pero si tiene 'fuerte' en ViewController, entonces esta vista no se puede desasignar, cuando está fuera de la pantalla. Lo que podría tener un fuerte impacto en la memoria del dispositivo y causar la desaceleración de la aplicación. (Por supuesto, el dispositivo tiene mucha memoria y definitivamente estarías bien en la aplicación de pantalla 5-10, pero en una aplicación enorme tendrás problemas)
bucherland
1
Cuando usamos débil? 1. Para los objetos de la interfaz de usuario, 2. delegados, 3. bloques (se debe usar débilSelf en lugar de self para evitar ciclos de memoria (como se mencionó anteriormente)
bucherland
1
Hay un error en esta gran respuesta: fuerte: "ARC lo libera automáticamente cuando haya terminado", esto no está bien. ARC liberará automáticamente objetos débiles cuando no haya punteros para ellos. Fuerte - es sinónimo de retener, por lo que el objeto se retiene y es nuestra responsabilidad hacer que el objeto sea nulo
Ashwin G
1
@RDC, ¿Qué defaultsignifica? Si lo uso @property (nonatomic) NSString *stringes strong? O assign? Porque ambos son valores predeterminados.
Iulian Onofrei
40

no atómico / atómico

  • no atómico es mucho más rápido que atómico
  • siempre use no atómico a menos que tenga un requisito muy específico para atómico, lo que debería ser raro (atomic no garantiza la seguridad del hilo, solo se detiene al acceder a la propiedad cuando otro hilo lo establece simultáneamente)

fuerte / débil / asignar

  • use fuerte para retener objetos - aunque la palabra clave retener es sinónimo, es mejor usar fuerte en su lugar
  • utilizar débil si solo desea un puntero al objeto sin retenerlo - útil para evitar ciclos de retención (es decir, delegados) - automáticamente anulará el puntero cuando se suelte el objeto
  • usar asignar para primitivas, exactamente como débil, excepto que no anula el objeto cuando se libera (configurado de forma predeterminada)

(Opcional)

Copiar

  • Úselo para crear una copia superficial del objeto
  • Es una buena práctica establecer siempre propiedades inmutables para copiar: dado que las versiones mutables se pueden pasar a propiedades inmutables, la copia garantizará que siempre se trate de un objeto inmutable
  • si se pasa un objeto inmutable, lo retendrá; si se pasa un objeto mutable, lo copiará

solo lectura

  • úselo para deshabilitar la configuración de la propiedad (evita que el código se compile si hay una infracción)
  • puede cambiar lo que entrega getter cambiando la variable directamente a través de su variable de instancia o dentro del método getter
Vadoff
fuente
@Sakthimuthiah tiene razón, debe corregir su respuesta.
Adela Toderici
@Sakthimuthiah es incorrecto (y cualquier otra persona que lo diga). Atomic NO lo hace seguro para subprocesos, aunque puede confundirse fácilmente debido a su comportamiento. Lea: stackoverflow.com/questions/12347236/…
Chris J
39

Hasta donde yo sé, strongy retainson sinónimos, entonces hacen exactamente lo mismo.

Entonces, weakes casi como assign, pero se establece automáticamente en nulo después de que el objeto al que apunta se desasigna.

Eso significa que simplemente puede reemplazarlos.

Sin embargo , hay un caso especial que he encontrado, donde tuve que usar assign, en lugar de weak. Digamos que tenemos dos propiedades delegateAssigny delegateWeak. En ambos se almacena nuestro delegado, que nos posee al tener la única referencia fuerte. El delegado está desasignando, por lo que nuestro -deallocmétodo también se llama.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

El delegado ya está en proceso de desasignación, pero aún no está desasignado completamente. ¡El problema es que las weakreferencias a él ya están anuladas! La propiedad delegateWeakcontiene nil, pero delegateAssigncontiene un objeto válido (con todas las propiedades ya liberadas y anuladas, pero aún válidas).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

Es un caso bastante especial, pero nos revela cómo funcionan esas weakvariables y cuándo se anulan.

Tricertops
fuente
20

El documento de Clang sobre Objective-C Automatic Reference Counting (ARC) explica claramente los calificadores y modificadores de propiedad:

Hay cuatro calificadores de propiedad:

  • __ autorreleasing
  • __ fuerte
  • __ * inseguro_reretenido *
  • __ débil

Un tipo no es trivialmente calificado por la propiedad si está calificado con __ autorreleasing , __ fuerte o __ débil .

Luego hay seis modificadores de propiedad para la propiedad declarada:

  • asignar implica __ * propiedad insegura * no retenida *.
  • copy implica __ propiedad fuerte , así como el comportamiento habitual de la semántica de copia en el setter.
  • retener implica __ fuerte propiedad.
  • fuerte implica __ fuerte propiedad.
  • * unsafe_unretained * implica __ * unsafe_unretained * propiedad.
  • débil implica __ propiedad débil .

Con la excepción de débil , estos modificadores están disponibles en modos no ARC.

En cuanto a la semántica, los calificadores de propiedad tienen un significado diferente en las cinco operaciones administradas : Lectura, Asignación, Inicialización, Destrucción y Mudanza, en las que la mayoría de las veces solo nos importa la diferencia en la operación de Asignación.

La asignación se produce al evaluar un operador de asignación. La semántica varía según la calificación:

  • Para __ objetos fuertes , el nuevo puntero se retiene primero; segundo, el valor l está cargado de semántica primitiva; tercero, el nuevo pointee se almacena en el valor l con semántica primitiva; y finalmente, se libera al viejo pointee. Esto no se realiza atómicamente; La sincronización externa debe usarse para hacer esto seguro frente a cargas y almacenes concurrentes.
  • Para __ objetos débiles , lvalue se actualiza para que apunte al nuevo puntero, a menos que el nuevo pointee sea un objeto que está actualmente en desasignación, en cuyo caso el lvalue se actualiza a un puntero nulo. Esto debe ejecutarse atómicamente con respecto a otras asignaciones al objeto, a las lecturas del objeto y al lanzamiento final del nuevo puntero.
  • Para los objetos __ * unsafe_unretained *, el nuevo puntero se almacena en el valor l utilizando semántica primitiva.
  • Para los objetos __ autorreleasing , el nuevo pointee se retiene, autoreleased y se almacena en el valor l utilizando semántica primitiva.

La otra diferencia en Lectura, Iniciación, Destrucción y Movimiento, consulte la Sección 4.2 Semántica en el documento .

Mingming
fuente
6

Para entender la referencia fuerte y débil, considere el siguiente ejemplo, suponga que tenemos un método llamado displayLocalVariable.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

En el método anterior, el alcance de la variable myName se limita al método displayLocalVariable, una vez que el método termina, la variable myName que contiene la cadena "ABC" se desasignará de la memoria.

Ahora, ¿qué pasa si queremos mantener el valor de la variable myName a lo largo de nuestro ciclo de vida del controlador de vista? Para esto, podemos crear la propiedad nombrada como nombre de usuario que tendrá una referencia fuerte a la variable myName (ver self.username = myName;en el código a continuación), como a continuación,

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Ahora, en el código anterior, puede ver que myName ha sido asignado a self.username y self.username tiene una referencia fuerte (como declaramos en la interfaz usando @property) a myName (indirectamente tiene una referencia fuerte a la cadena "ABC"). Por lo tanto, String myName no se desasignará de la memoria hasta que self.username esté activo.

  • Referencia débil

Ahora considere asignar myName a dummyName, que es una referencia débil, self.dummyName = myName; A diferencia de la referencia fuerte, Débil mantendrá myName solo hasta que haya una referencia fuerte a myName. Vea el código a continuación para comprender la referencia débil,

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

En el código anterior hay una referencia débil a myName (es decir, self.dummyName tiene una referencia débil a myName) pero no hay una referencia fuerte a myName, por lo tanto self.dummyName no podrá mantener el valor myName.

Ahora nuevamente considere el siguiente código,

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

En el código anterior, self.username tiene una referencia Strong a myName, por lo tanto self.dummyName ahora tendrá un valor de myName incluso después de que termine el método, ya que myName tiene una referencia Strong asociada.

Ahora, cada vez que hacemos una referencia fuerte a una variable, su recuento de retención aumenta en uno y la variable no conseguirá que el recuento de retención desasignado llegue a 0.

Espero que esto ayude.

Mahadev Mandale
fuente
2

Fuerte:

  • La propiedad no se destruirá, pero solo una vez que establezca la propiedad en cero, el objeto se destruirá
  • Por defecto, todas las variables de instancia y las variables locales son punteros fuertes.
  • Usas fuerte solo si necesitas retener el objeto.
  • Por lo general, utilizamos fuerte para UIViewControllers (elementos del elemento de la interfaz de usuario)
  • IOS 4 (no ARC) que podemos usar Retain KeyWord
  • IOS 5 (ARC) Podemos usar palabras clave fuertes

Ejemplo: @property (fuerte, no atómico) ViewController * viewController;

@synthesize viewController;

Débiles

Por defecto se obtiene automáticamente y se establece en nulo

  • Generalmente usamos débil para IBOutlets (UIViewController's Childs) y delegamos
  • lo mismo que asignar, no retener o liberar

Ejemplo: @property (débil, no atómico) IBOutlet UIButton * myButton;

@ sintetizar myButton;

Nikunj Patel
fuente
1

Las diferencias entre fuerte y retener:

  • En iOS4, fuerte es igual a retener
  • Significa que usted posee el objeto y lo mantiene en el montón hasta que ya no lo señale
  • Si escribe retener, funcionará automáticamente como fuerte

Las diferencias entre débil y asignar:

  • Una referencia "débil" es una referencia que no retiene y la conserva mientras alguien más la señale fuertemente
  • Cuando el objeto está "desasignado", el puntero débil se establece automáticamente en cero
  • Un atributo de propiedad "asignar" le dice al compilador cómo sintetizar la implementación del establecedor de la propiedad
Chen Rui
fuente