¿Cuál es la diferencia entre una referencia débil y una referencia sin propietario?

Swift tiene:

  • Referencias fuertes
  • Referencias Débiles
  • Referencias sin propietario

¿En qué se diferencia una referencia sin propietario de una referencia débil?

¿Cuándo es seguro usar una referencia sin propietario?

¿Las referencias sin dueño son un riesgo de seguridad como punteros colgantes en C / C ++?

Las referencias weak y unowned no crean una retención strong del objeto referido (es decir, no aumentan el conteo retenido para evitar que ARC desasigne el objeto referido).

Pero, ¿por qué dos palabras clave? Esta distinción tiene que ver con el hecho de que los tipos Optional están incorporados en el lenguaje Swift. Larga historia sobre ellos: los tipos opcionales ofrecen seguridad de memoria (esto funciona muy bien con las reglas de constructor de Swift, que son estrictas para proporcionar este beneficio).

Una referencia weak permite que la posibilidad de que sea nil (esto sucede automáticamente cuando el objeto al que se hace referencia es desasignado), por lo tanto, el tipo de propiedad debe ser opcional, por lo que usted, como progtwigdor, está obligado a verificarlo antes de usarlo ( básicamente, el comstackdor te obliga, en la medida de lo posible, a escribir código seguro).

Una referencia unowned supone que nunca se volverá nil durante su vida. Se debe establecer una referencia sin propietario durante la inicialización; esto significa que la referencia se definirá como un tipo no opcional que se puede usar de manera segura sin comprobaciones. Si de alguna manera el objeto al que se hace referencia es desasignado, la aplicación se bloqueará cuando se use la referencia sin propietario.

De los documentos de Apple :

Use una referencia débil siempre que sea válido para que la referencia se vuelva nula en algún momento de su vida útil. Por el contrario, use una referencia sin dueño cuando sepa que la referencia nunca será nula una vez que se haya establecido durante la inicialización.

En los documentos, hay algunos ejemplos que explican cómo conservar los ciclos y cómo romperlos. Todos estos ejemplos se extraen de los documentos .

Ejemplo para la palabra clave weak :

 class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? } class Apartment { let number: Int init(number: Int) { self.number = number } weak var tenant: Person? } 

Y ahora, para un poco de arte ASCII (deberías ir a ver los documentos , tienen bonitos diagtwigs):

 Person ===(strong)==> Apartment Person < ==(weak)===== Apartment 

El ejemplo de Person y Apartment muestra una situación en la que dos propiedades, ambas permitidas, tienen el potencial de causar un fuerte ciclo de referencia. Este escenario se resuelve mejor con una referencia débil. Ambas entidades pueden existir sin tener una dependencia estricta sobre la otra.

Ejemplo para la palabra clave unowned :

 class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } } class CreditCard { let number: UInt64 unowned let customer: Customer init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer } } 

En este ejemplo, un Customer puede o no tener una CreditCard , pero una CreditCard siempre se asociará con un Customer . Para representar esto, la clase Customer tiene una propiedad de card opcional, pero la clase CreditCard tiene una propiedad de customer no opcional (y sin propietario).

 Customer ===(strong)==> CreditCard Customer < ==(unowned)== CreditCard 

El ejemplo Customer and CreditCard muestra una situación en la que una propiedad que se permite que sea nula y otra propiedad que no puede ser nula tienen el potencial de causar un fuerte ciclo de referencia. Este escenario se resuelve mejor con una referencia sin propietario.

Nota de Apple:

Las referencias débiles deben declararse como variables para indicar que su valor puede cambiar en el tiempo de ejecución. Una referencia débil no se puede declarar como una constante.

También hay un tercer escenario cuando ambas propiedades siempre deben tener un valor, y ninguna de las propiedades debe ser nula una vez que se haya completado la inicialización.

Y también existen los escenarios de ciclo de retención clásicos que se deben evitar al trabajar con cierres.

Para esto, te animo a que visites los documentos de Apple o leas el libro .

Q1. ¿En qué se diferencia una “referencia sin propietario” de una “referencia débil”?

Débil referencia:

Una referencia débil es una referencia que no mantiene una retención fuerte en la instancia a la que hace referencia, por lo que no impide que ARC elimine la instancia referenciada. Debido a que las referencias débiles pueden tener “ningún valor”, debe declarar que cada referencia débil tiene un tipo opcional. (Apple Docs)

Referencia sin propietario:

Al igual que las referencias débiles, una referencia sin dueño no mantiene un fuerte control sobre la instancia a la que se refiere. Sin embargo, a diferencia de una referencia débil, se asume que una referencia sin dueño siempre tiene un valor. Debido a esto, una referencia sin dueño siempre se define como un tipo no opcional. (Apple Docs)

Cuándo usar cada uno:

Use una referencia débil siempre que sea válido para que la referencia se vuelva nula en algún momento de su vida útil. Por el contrario, use una referencia sin dueño cuando sepa que la referencia nunca será nula una vez que se haya establecido durante la inicialización. (Apple Docs)


Q2. ¿Cuándo es seguro usar una “referencia sin dueño”?

Como se citó anteriormente, se asume que una referencia sin dueño siempre tiene un valor. Por lo tanto, solo debe usarlo cuando esté seguro de que la referencia nunca será nula. Los documentos de Apple ilustran un caso de uso para referencias sin propietario a través del siguiente ejemplo.

Supongamos que tenemos dos clases Customer y CreditCard . Un cliente puede existir sin una tarjeta de crédito, pero una tarjeta de crédito no existirá sin un cliente, es decir, se puede suponer que una tarjeta de crédito siempre tendrá un cliente. Entonces, deberían tener la siguiente relación:

 class Customer { var card: CreditCard? } class CreditCard { unowned let customer: Customer } 

Q3. La referencia de “referencia sin dueño” es un riesgo de seguridad como “indicadores colgantes” en C / C ++

No lo creo.

Como las referencias sin propietario son solo referencias débiles que tienen un valor garantizado, no deberían ser un riesgo para la seguridad de ninguna manera. Sin embargo, si intenta acceder a una referencia sin propietario después de que la instancia a la que hace referencia es desasignada, desencadenará un error de tiempo de ejecución y la aplicación fallará.

Ese es el único riesgo que veo con eso.

Enlace a Apple Docs

Si el yo puede ser nulo en el uso de cierre [yo débil] .

Si el yo nunca será nulo en el uso de cierre [yo sin dueño] .

Si se cuelga cuando usas [self sin dueño], entonces el self probablemente sea nulo en algún momento de ese cierre y probablemente necesites usar [weak self] en su lugar.

Eche un vistazo a los ejemplos sobre el uso de cierres fuertes , débiles y sin dueño :

https://developer.apple.com/library/ios/documentation/swift/conceptual/swift_programming_language/AutomaticReferenceCounting.html

Extractos del enlace

Pocos puntos finales

  • Para determinar si incluso tiene que preocuparse por personas fuertes, débiles o sin dueño, pregunte: “¿Estoy lidiando con tipos de referencia?”. Si está trabajando con Structs o Enums, ARC no administra la memoria para esos tipos y ni siquiera necesita preocuparse por especificar weak o unowned para esas constantes o variables.
  • Las referencias fuertes están bien en las relaciones jerárquicas donde el padre hace referencia al niño, pero no al revés. De hecho, las referencias fuertes son el tipo de referencia más adecuado la mayor parte del tiempo.
  • Cuando dos instancias están opcionalmente relacionadas entre sí, asegúrese de que una de esas instancias contenga una referencia débil a la otra.
  • Cuando dos instancias están relacionadas de tal manera que una de las instancias no puede existir sin la otra, la instancia con la dependencia obligatoria necesita contener una referencia sin propietario a la otra instancia.

Del libro de Jon Hoffman “Mastering Swift 4.”:

La diferencia entre una referencia débil y una referencia sin propietario es que la instancia a la que hace referencia una referencia débil puede ser nula, mientras que la instancia a la que hace referencia una referencia sin propietario no puede ser nula. Esto significa que cuando usamos una referencia débil, la propiedad debe ser una propiedad opcional, ya que puede ser nula.

Las referencias sin propietario son un tipo de referencia débil utilizada en el caso de una relación de la misma vida entre dos objetos, cuando un objeto solo debería ser propiedad de otro objeto. Es una forma de crear un enlace inmutable entre un objeto y una de sus propiedades.

En el ejemplo dado en el video WWDC rápido intermedio, una persona posee una tarjeta de crédito, y una tarjeta de crédito solo puede tener un titular. En la tarjeta de crédito, la persona no debe ser una propiedad opcional, porque no desea tener una tarjeta de crédito flotando con un solo propietario. Podría romper este ciclo haciendo que la propiedad del titular en el crédito sea una referencia débil, pero eso también requiere que sea opcional y variable (en lugar de constante). La referencia sin propietario en este caso significa que aunque CreditCard no tiene una participación propietaria en una Persona, su vida depende de ello.

 class Person { var card: CreditCard? } class CreditCard { unowned let holder: Person init (holder: Person) { self.holder = holder } }