6

我总是使用[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其他地方呢?

4

3 回答 3

11

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

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

人们可能会考虑其他场景/边缘情况,但这些是基本方法。

于 2019-02-16T04:57:23.497 回答
4

你说:

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
    }
})
于 2019-02-16T02:17:22.767 回答
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()
})
于 2019-02-16T02:39:12.763 回答