在 swift 闭包中使用 `[weak self]` 是正确的方法吗?

Is it the right way using `[weak self]` in swift closure?

我总是在 swift 闭包中使用 [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 吗?

你说:

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

不!你没有保留self,所以理论上在执行闭包的过程中随时可能变成nil。它可能不会,但 "probably" 还不够好。感叹号总是让人崩溃。

跳弱强之舞,并且跳得正确:

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

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

您的模式存在竞争条件。如果 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()
    }
    

    有时你需要“弱自强自舞”(前两种选择),但在这里似乎不是这样。这可能就足够了。

人们可能会考虑其他 scenarios/edge 个案例,但这些是基本方法。