formato documento como citar apa swift memory-management automatic-ref-counting weak-references dangling-pointer

swift - documento - ¿Cuál es la diferencia entre una referencia débil y una referencia sin dueño?



et al apa (6)

Swift tiene:

  • Referencias fuertes
  • Referencias débiles
  • Referencias sin propiedad

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

¿Cuándo es seguro usar una referencia sin dueño?

¿Las referencias sin propiedad son un riesgo de seguridad como los punteros colgantes en C / C ++?


Del libro de Jon Hoffman "Mastering Swift 4.":

La diferencia entre una referencia débil y una referencia sin propiedad es que la instancia a la que se refiere una referencia débil puede ser nula, mientras que la instancia a la que se refiere una referencia sin propiedad 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.


Extractos de andrewcbancroft.com/2015/05/08/…

Pocos puntos finales

  • Para determinar si incluso necesita preocuparse por fuertes, débiles o sin dueño, pregunte: “¿Estoy tratando con tipos de referencia”? Si está trabajando con Structs o Enums, ARC no está administrando la memoria para esos tipos y ni siquiera necesita preocuparse por especificar debilidad o falta de propiedad para esas constantes o variables.
  • Las referencias fuertes están bien en las relaciones jerárquicas donde el padre hace referencia al hijo, pero no al revés. De hecho, las referencias fuertes son el tipo de referencia más apropiado la mayor parte del tiempo.
  • Cuando dos instancias están relacionadas opcionalmente 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 debe tener una referencia sin propiedad para la otra instancia.

Las referencias no adquiridas son un tipo de referencia débil que se utiliza en el caso de una relación en la misma vida útil entre dos objetos, cuando un objeto solo debe 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 de WWDC 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, ya que no desea tener una tarjeta de crédito flotando con un solo propietario. Podría romper este ciclo haciendo que la propiedad del titular del crédito sea una referencia débil, pero eso también requiere que sea opcional y variable (en lugar de constante). La referencia no adquirida en este caso significa que aunque CreditCard no tiene una participación propietaria en una Persona, su vida depende de ella.

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


Si el yo pudiera ser nulo en el cierre, use [yo débil] .

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

Si se bloquea cuando usas [yo sin dueño], entonces el yo es probablemente nulo en algún momento de ese cierre y probablemente necesites usar [el yo débil] en su lugar.

Echa 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


Tanto weak referencias weak como las unowned no crean un strong control sobre el objeto referido (es decir, no aumentan el conteo de retenciones 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. Una larga historia corta sobre ellos: los tipos opcionales ofrecen seguridad de memoria (esto funciona a la perfección con las reglas de construcción de Swift, que son estrictas para brindar este beneficio).

Una referencia weak permite que su posibilidad se vuelva nil (esto sucede automáticamente cuando se desasigna el objeto al que se hace referencia), por lo que el tipo de su propiedad debe ser opcional, por lo que usted, como programador, está obligado a verificarlo antes de usarlo ( básicamente, el compilador le obliga, tanto como pueda, a escribir código seguro).

Una referencia unowned presume que nunca se volverá nil durante su vida útil. Se debe establecer una referencia sin propiedad durante la inicialización; esto significa que la referencia se definirá como un tipo no opcional que se puede usar de manera segura sin controles. Si de alguna manera el objeto al que se hace referencia se desasigna, la aplicación se bloqueará cuando se use la referencia sin dueño.

De los documentos de Apple :

Use una referencia débil siempre que sea válida para que esa referencia se vuelva nula en algún momento durante su vida útil. A la inversa, use una referencia sin propiedad 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 analizan los ciclos de retención 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 algunas obras de arte ASCII (deberías ir a ver los documentos ; tienen diagramas bonitos):

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

El ejemplo de Person y Apartment muestra una situación en la que dos propiedades, que pueden ser nulas, 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 estará asociada 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 dueño).

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

El ejemplo del Customer y la CreditCard muestra una situación en la que una propiedad que puede ser nula y otra propiedad que no puede ser nula tienen el potencial de causar un ciclo de referencia sólido. Este escenario se resuelve mejor con una referencia sin dueño.

Nota de Apple:

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

También hay un tercer escenario en el que ambas propiedades siempre deberían tener un valor, y ninguna de ellas debería ser nula una vez que se haya completado la inicialización.

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

Para esto, te animo a visitar los documentos de Apple o leer el libro .


Q1. ¿En qué se diferencia una "referencia sin dueño" de una "referencia débil"?

Referencia débil:

Una referencia débil es una referencia que no mantiene un fuerte control sobre la instancia a la que hace referencia, y por lo tanto no impide que ARC elimine la instancia a la que se hace referencia. Debido a que se permite que las referencias débiles no tengan "valor", debe declarar que cada referencia débil tiene un tipo opcional. (Apple Docs)

Referencia sin propiedad:

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

Cuándo usar cada uno:

Use una referencia débil siempre que sea válida para que esa referencia se vuelva nula en algún momento durante su vida útil. A la inversa, use una referencia sin propiedad 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 mencionó anteriormente, se supone 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 Apple Docs ilustran un caso de uso para referencias sin propiedad 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. Por lo tanto, deben tener la siguiente relación:

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

Q3. Las referencias "sin propiedad" son un riesgo de seguridad como los "punteros colgantes" en C / C ++

No lo creo.

Dado que las referencias sin propiedad son solo referencias débiles que tienen garantizado un valor, no debe ser un riesgo de seguridad de ninguna manera. Sin embargo, si intenta acceder a una referencia sin dueño después de que se desasigne la instancia a la que hace referencia, se activará un error de tiempo de ejecución y la aplicación se bloqueará.

Ese es el único riesgo que veo con él.

Enlace a Apple Docs