Siempre uso [weak self] en el cierre rápido para evitar el ciclo de referencia. Aquí está el código a continuación, ¿es la forma correcta?
someTask(completion: {[weak self] (result) in if self == nil { return } //is it safe when reach here? self!.xxx = yyy self!.doLongTermWork() self!.finish() //will crash when self is nil? }) El yo débil no mantiene un control fuerte sobre la instancia. Entonces, cuando self.doLongTermWork() , ¿ self se establecerá en nil nuevamente en otro lugar?
Su patrón tiene condición de carrera. Si self se desasignó exactamente al mismo tiempo que se ejecutaba el cierre del controlador de finalización, podría bloquearse. Como regla general, evite usar el ! operador de desenvolvimiento forzado si puede.
Me inclinaría por el patrón de "salida anticipada" de la guard (reduciendo las llaves anidadas, haciendo que el código sea más fácil de leer). La solución estándar de Swift 4.2 es:
someTask { [weak self] result in guard let self = self else { return } self.xxx = yyy self.doLongTermWork() self.finish() }Antes de Swift 4.2, que implementó SE-0079 , tendríamos que hacer algo como:
someTask { [weak self] result in guard let strongSelf = self else { return } strongSelf.xxx = yyy strongSelf.doLongTermWork() strongSelf.finish() } Puede ver por qué preferimos la mejora de Swift 4.2, ya que esta sintaxis strongSelf es elegante.
La otra alternativa obvia es simplemente:
someTask { [weak self] result in self?.xxx = yyy self?.doLongTermWork() self?.finish() }A veces se necesita el “baile del yo débil - yo fuerte” (las dos primeras alternativas), pero no parece ser el caso aquí. Es probable que esto sea suficiente.
Hay otros escenarios/casos extremos que uno podría contemplar, pero estos son los enfoques básicos.
Tu dijiste:
someTask(completion: {[weak self] (result) in if self == nil { return } //is it safe when reach here? self!.xxx = yyy }) ¡No! No ha retenido self , por lo que, en teoría, podría volverse nil en cualquier momento durante la ejecución del cierre. Probablemente no lo hará, pero "probablemente" no es lo suficientemente bueno. Y los signos de exclamación son siempre una invitación a estrellarse.
Haz el baile débil-fuerte, y hazlo correctamente:
someTask(completion: {[weak self] (result) in if let self = self { // or let `self` before Swift 4 // here, self is safe, because you made the reference strong again self.xxx = yyy } })Puedes usarlo así desde Swift 4.2
someTask(completion: {[weak self] (result) in guard let self = self { return } //it safe when reach here always self.xxx = yyy self.doLongTermWork() self.finish() })