快速关闭时使用`[weak self]`是正确的方法吗?

时间:2019-02-16 02:05:00

标签: swift closures weak

我总是在快速关闭中使用[weak self]来防止引用循环。 这是下面的代码,这是正确的方法吗?

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?
    })

弱自我并不能完全控制实例。因此,当self.doLongTermWork()时,self是否会在其他地方再次设置为nil

3 个答案:

答案 0 :(得分:2)

您说:

someTask(completion: {[weak self] (result) in
    if self == nil {  
        return
    }
    //is it safe when reach here? 
    self!.xxx = yyy
})

不!您尚未保留self,因此从理论上讲,它可能在执行闭包期间随时变为nil。可能不会,但是“可能”还不够好。而且,感叹号始终是崩溃的邀请。

做弱而有力的舞蹈,并正确地做

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
    }
})

答案 1 :(得分:1)

您的模式具有比赛条件。如果self在完成处理程序关闭执行的同时被释放,则可能会崩溃。通常,请尽量避免使用!强制展开运算符。

  1. 我倾向于使用guard“提前退出”模式(减少嵌套的花括号,使代码更易于阅读)。标准的Swift 4.2解决方案是:

    someTask { [weak self] result in
        guard let self = self else { return }
    
        self.xxx = yyy
        self.doLongTermWork()
        self.finish()
    }
    
  2. 在实现SE-0079的Swift 4.2之前,我们必须做类似的事情:

    someTask { [weak self] result in
        guard let strongSelf = self else { return }
    
        strongSelf.xxx = yyy
        strongSelf.doLongTermWork()
        strongSelf.finish()
    }
    

    您会看到为什么我们偏爱Swift 4.2改进的原因,因为这种strongSelf语法不雅观。

  3. 另一个明显的选择是:

    someTask { [weak self] result in
        self?.xxx = yyy
        self?.doLongTermWork()
        self?.finish()
    }
    

    有时您需要“弱自我-强自我舞蹈”(前两种选择),但在这里似乎并非如此。这可能就足够了。

还有其他可能需要考虑的场景/边缘情况,但这是基本的方法。

答案 2 :(得分:0)

您可以在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()
})