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

Resuelto Ian Ringrose asked hace 10 años • 8 respuestas

Swift tiene:

  • Referencias fuertes
  • Referencias débiles
  • Referencias sin dueño

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

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

¿Las referencias sin propietario son un riesgo para la seguridad, como los punteros colgantes en C/C++?

Ian Ringrose avatar Jun 03 '14 16:06 Ian Ringrose
Aceptado

Ambas referencias weaky unownedno crean una strongretención en el objeto referido (es decir, no aumentan el recuento de retención 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 Optionallos tipos están integrados en el lenguaje Swift. Para resumir, los tipos opcionales ofrecen seguridad de memoria (esto funciona muy bien con las reglas del constructor de Swift , que son estrictas para brindar este beneficio).

Una weakreferencia permite la posibilidad de que se convierta nil(esto sucede automáticamente cuando el objeto referenciado se desasigna), por lo tanto, el tipo de su propiedad debe ser opcional, por lo que usted, como programador, está obligado a verificarlo antes de usarlo (básicamente el El compilador te obliga, en la medida de lo posible, a escribir código seguro).

Una unownedreferencia supone que nunca lo será nildurante 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 utilizar de forma segura sin comprobaciones. Si de alguna manera se desasigna el objeto al que se hace referencia, la aplicación se bloqueará cuando se utilice la referencia sin propietario.

De los documentos de Apple :

Utilice una referencia débil siempre que sea válida para que esa referencia se vuelva nula en algún momento durante su vida. Por el contrario, utilice una referencia sin propietario 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 están extraídos de los documentos .

Ejemplo de la weakpalabra clave:

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 ver algo de arte ASCII (deberías ver los documentos , tienen diagramas bonitos):

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

El ejemplo Persony Apartmentmuestra una situación en la que dos propiedades, a las cuales se les permite ser nulas, tienen el potencial de causar un ciclo de referencia fuerte. Este escenario se resuelve mejor con una referencia débil. Ambas entidades pueden existir sin tener una dependencia estricta de la otra.

Ejemplo de la unownedpalabra clave:

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, a Customerpuede tener o no un CreditCard, pero a CreditCard siempre estará asociado con un Customer. Para representar esto, la clase tiene una propiedad Customeropcional , pero la clase tiene una propiedad no opcional (y sin propietario) .cardCreditCardcustomer

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

El ejemplo Customery CreditCardmuestra una situación en la que una propiedad a la que se le permite ser nula y otra propiedad que no puede ser nula tiene 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 tiempo de ejecución. Una referencia débil no puede declararse como constante.

También existe un tercer escenario en el que ambas propiedades siempre deben tener un valor y ninguna de ellas debe ser nula una vez completada la inicialización.

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

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

Ilea Cristian avatar Sep 24 '2014 19:09 Ilea Cristian

P1. ¿En qué se diferencia una “referencia sin propietario” 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. (Documentos de Apple)

Referencia sin dueño:

Al igual que las referencias débiles, una referencia sin propietario no mantiene un control firme sobre la instancia a la que hace referencia. Sin embargo, a diferencia de una referencia débil, se supone que una referencia sin propietario siempre tiene un valor. Debido a esto, una referencia sin propietario siempre se define como un tipo no opcional. (Documentos de Apple)

Cuándo usar cada uno:

Utilice una referencia débil siempre que sea válida para que esa referencia se vuelva nula en algún momento durante su vida. Por el contrario, utilice una referencia sin propietario cuando sepa que la referencia nunca será nula una vez que se haya establecido durante la inicialización. (Documentos de Apple)


P2. ¿Cuándo es seguro utilizar una “referencia sin propietario”?

Como se mencionó anteriormente, se supone que una referencia sin propietario siempre tiene un valor. Por lo que sólo debes usarlo cuando estés seguro de que la referencia nunca será nula. Apple Docs ilustra un caso de uso para referencias sin propietario mediante el siguiente ejemplo.

Supongamos que tenemos dos clases Customery 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
}

P3. ¿La referencia de "referencia sin propietario" es un riesgo de seguridad como los "punteros colgantes" en C/C++?

No me parece.

Dado que las referencias sin propietario son solo referencias débiles cuyo valor está garantizado, no debería representar un riesgo para la seguridad de ninguna manera. Sin embargo, si intenta acceder a una referencia sin propietario después de que se cancele la asignación de la instancia a la que hace referencia, se generará un error de tiempo de ejecución y la aplicación se bloqueará.

Ese es el único riesgo que le veo.

Enlace a documentos de Apple

Myxtic avatar Oct 21 '2014 17:10 Myxtic