unowned traduccion strong cycles swift weak-references

swift - traduccion - ¿A dónde va el ser débil?



weak self swift 4 (1)

A menudo hago esto,

let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { beep() }

y en una aplicación a menudo hacemos esto

tickle.fresh(){ msg in paint() }

pero si haces esto

let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { tickle.fresh(){ msg in paint() } }

por supuesto que tienes que hacer esto

let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in tickle.fresh(){ msg in self?.paint() } }

o tal vez esto

let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { tickle.fresh(){ [weak self] msg in self?.paint() } }

o tal vez esto

let when = DispatchTime.now() + 2.0 DispatchQueue.main.asyncAfter(deadline: when) { [weak self] _ in tickle.fresh(){ [weak self] msg in self?.paint() } }

¿Qué deberíamos hacer?

Las tres sugerencias parecen funcionar perfectamente. ¿Cuál es la profundidad de significado aquí? ¿Y cuál debería hacer? ¿Es una referencia fuerte a una referencia débil, una referencia débil o fuerte? Ser o no ser? ¡Esa es la pregunta!


En primer lugar, tenga en cuenta que generalmente no tiene que preocuparse por los ciclos de retención con DispatchQueue.main.asyncAfter , ya que el cierre se ejecutará en algún momento. Por lo tanto, ya sea que se capture o no débilmente, no estará creando un ciclo de retención permanente (suponiendo que tickle.fresh tampoco lo haga).

Ya sea que coloque o no una lista de captura [weak self] en el asyncAfter externo, el cierre depende completamente de si desea que el self se retenga hasta que se llame al cierre (después de la hora establecida). Si no necesita que el self permanezca vivo hasta que se llame al cierre, ponga [weak self] , si lo hace, entonces no lo haga.

Si pones o no un [weak self] en el cierre interior (el que pasó a tickle.fresh ) depende de si ya has capturado débilmente el self en el cierre exterior. Si no lo has hecho, entonces puedes poner [weak self] para evitar que el cierre interno lo retenga. Sin embargo, si el cierre externo ya ha capturado débilmente el self , entonces el cierre interno ya tendrá una referencia débil al self , por lo que agregar [weak self] al cierre interior no tendrá ningún efecto.

Entonces, para resumir:

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { tickle.fresh { msg in self.paint() } }

self será retenido tanto por el cierre externo como por el interno.

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in tickle.fresh { msg in self?.paint() } }

self no será retenido por ningún cierre.

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in tickle.fresh { [weak self] msg in self?.paint() } }

Igual que lo anterior, el [weak self] adicional para el cierre interno no tiene ningún efecto, ya que el cierre externo ya captura débilmente al self .

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { tickle.fresh { [weak self] msg in self?.paint() } }

self será retenido por el cierre exterior, pero no por el cierre interno.

Por supuesto, puede ser que no quieras que el cierre externo te retenga a ti mismo , pero quieres que el cierre interno lo retenga. En tales casos, puede declarar una variable local en el cierre exterior para mantener una referencia fuerte a self , cuando luego puede capturar en el cierre interior:

DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in guard let strongSelf = self else { return } tickle.fresh { msg in strongSelf.paint() } }

Ahora, el self no se mantendrá vivo con el cierre exterior, pero una vez que se llame, si el self todavía existe, se mantendrá vivo con el cierre interior hasta que ese cierre se haya desasignado.

En respuesta a:

¿Es una referencia fuerte a una referencia débil, una referencia débil o fuerte?

Las referencias débiles se implementan como opcionales, que son tipos de valor. Por lo tanto, no puede tener una referencia fuerte a uno directamente ; en lugar de eso, primero debe desenvolverlo y luego tomar una referencia fuerte a la instancia subyacente. En este caso, simplemente está tratando con una referencia fuerte (exactamente como mi ejemplo anterior con strongSelf ).

Sin embargo, si una referencia débil está en el recuadro (esto sucede con la captura de cierre, el tipo de valor se colocará en un recuadro asignado por el montón), de hecho, puede tener una fuerte referencia a ese recuadro. El efecto de esto es equivalente a una referencia débil a la instancia original, solo tienes un bit invisible de indirection extra.

De hecho, esto es exactamente lo que sucede en el ejemplo en el que el cierre exterior se captura débilmente y el cierre interior "captura fuertemente" esa referencia débil. El efecto es que ni el cierre se conserva a self .