En la sesión de WWDC 2014 403 Intermedio Swift y transcripción , hubo la siguiente diapositiva
El orador dijo en ese caso, si no lo usamos [unowned self]
allí, será una pérdida de memoria. ¿Significa que siempre debemos usar el [unowned self]
cierre interior?
En la línea 64 de ViewController.swift de la aplicación Swift Weather , no lo uso [unowned self]
. Pero actualizo la interfaz de usuario usando algunos @IBOutlet
s como self.temperature
y self.loadingIndicator
. Puede estar bien porque todos los @IBOutlet
s que definí son weak
. Pero por seguridad, ¿deberíamos usar siempre [unowned self]
?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
swift
automatic-ref-counting
Jake Lin
fuente
fuente
onChange
debe ser un[weak self]
cierre, ya que es una propiedad pública (internamente, pero aún así), por lo que otro objeto podría obtener y almacenar el cierre, manteniendo el objeto TempNotifier alrededor (indefinidamente si el objeto en uso no soltó elonChange
cierre hasta que vio queTempNotifier
se había ido, a través de su propia referencia débil aTempNotifier
) . Sivar onChange …
fueraprivate var onChange …
así[unowned self]
, sería correcto. Sin embargo, no estoy 100% seguro de esto; alguien me corrija por favor si me equivoco.[]
? No puedo encontrar la explicación en los documentos de Apple.{}
es el cierre vacío (la instancia del cierre) como predeterminado (no hace nada),(Int) -> Void
es la definición de cierre.Respuestas:
No, definitivamente hay momentos en los que no querrás usar
[unowned self]
. A veces, desea que el cierre se capture a sí mismo para asegurarse de que todavía esté presente para cuando se cierre.Ejemplo: hacer una solicitud de red asincrónica
Si realiza una solicitud de red asincrónica , desea que se retenga el cierre
self
cuando finalice la solicitud. De lo contrario, ese objeto puede haber sido desasignado, pero aún así desea poder manejar el final de la solicitud.Cuando usar
unowned self
oweak self
El único momento en el que realmente desea usar
[unowned self]
o[weak self]
es cuando crearía un ciclo de referencia fuerte . Un ciclo de referencia fuerte es cuando hay un ciclo de propiedad en el que los objetos terminan siendo propietarios (tal vez a través de un tercero) y, por lo tanto, nunca se desasignarán porque ambos se aseguran de que el otro se quede.En el caso específico de un cierre, solo necesita darse cuenta de que cualquier variable a la que se haga referencia dentro de ella, se "apropia" del cierre. Mientras el cierre esté alrededor, se garantiza que esos objetos estarán alrededor. La única forma de detener esa propiedad es hacer el
[unowned self]
o[weak self]
. Entonces, si una clase posee un cierre, y ese cierre captura una referencia fuerte a esa clase, entonces tiene un ciclo de referencia fuerte entre el cierre y la clase. Esto también incluye si la clase posee algo que posee el cierre.Específicamente en el ejemplo del video
En el ejemplo de la diapositiva,
TempNotifier
posee el cierre a través de laonChange
variable miembro. Si no declararanself
comounowned
, el cierre también sería propioself
creando un ciclo de referencia fuerte.Diferencia entre
unowned
yweak
La diferencia entre
unowned
yweak
es queweak
se declara como Opcional mientrasunowned
que no lo es. Al declararlo,weak
puede manejar el caso de que podría ser nulo dentro del cierre en algún momento. Si intenta acceder a unaunowned
variable que resulta ser nula, se bloqueará todo el programa. Por lo tanto, solo useunowned
cuando sea positivo que la variable siempre estará alrededor mientras el cierre esté alrededorfuente
[weak self]
en una solicitud de red asíncrona es en un controlador de vista donde esa solicitud se usa para llenar la vista. Si el usuario retrocede, ya no necesitamos llenar la vista, ni necesitamos una referencia al controlador de vista.weak
las referencias también se establecennil
cuando el objeto se desasigna.unowned
las referencias no lo son.unowned
se utiliza paranon-Optional
mientrasweak
se utiliza paraOptional
lo que nuestroself
esOptional
onon-optional
?Actualización 11/2016
Escribí un artículo sobre esto extendiendo esta respuesta (buscando en SIL para entender lo que hace ARC), échale un vistazo aquí .
Respuesta original
Las respuestas anteriores realmente no dan reglas sencillas sobre cuándo usar una sobre la otra y por qué, así que permítanme agregar algunas cosas.
La discusión no propia o débil se reduce a una cuestión de vida útil de la variable y el cierre que hace referencia a ella.
Escenarios
Puede tener dos escenarios posibles:
El cierre tiene la misma vida útil de la variable, por lo que el cierre será accesible solo hasta que la variable sea accesible . La variable y el cierre tienen la misma vida útil. En este caso, debe declarar la referencia como no propiedad . Un ejemplo común es el
[unowned self]
utilizado en muchos ejemplos de cierres pequeños que hacen algo en el contexto de sus padres y que no se hace referencia a ellos en ningún otro lugar, no sobreviven a sus padres.La vida útil del cierre es independiente de la de la variable, aún se puede hacer referencia al cierre cuando la variable ya no es accesible. En este caso, debe declarar la referencia como débil y verificar que no sea nula antes de usarla (no fuerce el desenvolvimiento). Un ejemplo común de esto es el
[weak delegate]
que puede ver en algunos ejemplos de cierre haciendo referencia a un objeto delegado completamente no relacionado (de por vida).Uso actual
Entonces, ¿cuál deberías / deberías usar la mayoría de las veces?
Citando a Joe Groff de Twitter :
Encontrará más información sobre
*
el funcionamiento interno no propietario aquí .*
Por lo general, también se conoce como sin propietario (seguro) para indicar que se realizan verificaciones de tiempo de ejecución (que provocan un bloqueo por referencias no válidas) antes de acceder a la referencia sin propietario.fuente
Pensé que agregaría algunos ejemplos concretos específicamente para un controlador de vista. Muchas de las explicaciones, no solo aquí en Stack Overflow, son realmente buenas, sino que trabajo mejor con ejemplos del mundo real (@drewag tuvo un buen comienzo en esto):
weak
, utilice las solicitudes , porque son de larga duración. El controlador de vista podría cerrarse antes de que se complete la solicitud, por lo queself
ya no apunta a un objeto válido cuando se llama al cierre.Si tiene un cierre que maneja un evento en un botón. Esto puede deberse a
unowned
que tan pronto como el controlador de vista desaparece, el botón y cualquier otro elemento al que haga referenciaself
desaparece al mismo tiempo. El bloque de cierre también desaparecerá al mismo tiempo.fuente
weak
lugar deunowned
¿verdad?Si el self puede ser nulo en el cierre, use [self débil] .
Si el self nunca será nulo en el cierre, use [self sin propietario] .
La documentación de Apple Swift tiene una gran sección con imágenes que explican la diferencia entre el uso de cierres fuertes , débiles y no propios:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html
fuente
Aquí hay citas brillantes de los foros de desarrolladores de Apple que describen detalles deliciosos:
unowned
vsunowned(safe)
vsunowned(unsafe)
unowned
vsweak
Actualización: en Swift moderno,
weak
internamente utiliza el mismo mecanismo que lounowned
hace . Entonces, esta comparación es incorrecta porque compara Objective-Cweak
con Swiftunonwed
.Razones
Emocionado, ¿eh?
fuente
Hay algunas respuestas geniales aquí. Pero los cambios recientes en la forma en que Swift implementa referencias débiles deberían cambiar las decisiones débiles de uso propio de todos frente a las de uso propio no deseadas. Anteriormente, si necesitabas el mejor rendimiento, usar un self sin dueño era superior al self débil, siempre que pudieras estar seguro de que el self nunca sería nulo, porque acceder al self sin propietario es mucho más rápido que acceder al self débil.
Pero Mike Ash ha documentado cómo Swift ha actualizado la implementación de vars débiles para usar las mesas auxiliares y cómo esto mejora sustancialmente el auto rendimiento débil.
https://mikeash.com/pyblog/friday-qa-2017-09-22-swift-4-weak-references.html
Ahora que no hay una penalización de rendimiento significativa para uno mismo débil, creo que deberíamos usarlo de forma predeterminada en el futuro. El beneficio del self débil es que es opcional, lo que hace que sea mucho más fácil escribir un código más correcto, es básicamente la razón por la que Swift es un lenguaje tan bueno. Puede pensar que sabe qué situaciones son seguras para el uso de personas sin propiedad, pero mi experiencia al revisar muchos otros códigos de desarrolladores es, la mayoría no. He solucionado muchos bloqueos en los que se desasignó self sin propietario, generalmente en situaciones en las que un subproceso de fondo se completa después de que se desasigna un controlador.
Los errores y las fallas son las partes de programación que requieren más tiempo, son más dolorosas y costosas. Haz tu mejor esfuerzo para escribir el código correcto y evitarlos. Recomiendo que sea una regla no forzar nunca las opciones opcionales de desenvolver y nunca usar un yo sin propietario en lugar de uno débil. No perderá nada perdido las veces que el desenvolvimiento forzado y el yo sin dueño en realidad están a salvo. Pero ganará mucho eliminando errores y errores difíciles de encontrar.
fuente
weak
que no se pueda usar en lugar de ununowned
?De acuerdo con Apple-doc
Ejemplo
fuente
Si nada de lo anterior tiene sentido:
tl; dr
Explicación:
Obtuve lo siguiente a continuación en: enlace débil no propiedad . Por lo que deduje, el yo sin dueño no puede ser nulo, pero el yo débil puede ser, y el yo sin dueño puede conducir a indicadores colgantes ... algo infame en Objective-C. Espero eso ayude
Las referencias no propias, como las referencias débiles, no aumentan el recuento de retención del objeto que se refiere. Sin embargo, en Swift, una referencia no propiedad tiene el beneficio adicional de no ser Opcional . Esto los hace más fáciles de administrar en lugar de recurrir al uso de enlaces opcionales. Esto no es diferente a los opcionales implícitamente sin envolver. Además, las referencias no propiedad no son cero . Esto significa que cuando el objeto se desasigna, no pone a cero el puntero. Esto significa que el uso de referencias no propias puede, en algunos casos, conducir a punteros colgantes. Para los nerds que recuerdan los días de Objective-C como lo hago yo, las referencias no propiedad se asignan a referencias no seguras y no retenidas.
Aquí es donde se vuelve un poco confuso.
Ambos pueden usarse para romper los ciclos de retención. Entonces, ¿cuándo los usamos?
Según los documentos de Apple :
fuente
fuente