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 sí 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
.