我总是在快速闭包中使用[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
吗?
您的模式具有争用条件。如果在执行完成处理程序闭包的同时解除分配self
,则可能会崩溃。作为一般规则,如果可以,请避免使用!
强制解包运算符。
-
我倾向于
guard
"提前退出"模式(减少嵌套大括号,使代码更易于阅读)。标准的 Swift 4.2 解决方案是:someTask { [weak self] result in guard let self = self else { return } self.xxx = yyy self.doLongTermWork() self.finish() }
-
在实现 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
语法是不优雅的。 -
另一个明显的选择只是:
someTask { [weak self] result in self?.xxx = yyy self?.doLongTermWork() self?.finish() }
有时你需要"弱自我 - 强自我舞蹈"(前两种选择),但这里似乎并非如此。这可能就足够了。
人们可能会考虑其他场景/边缘情况,但这些是基本方法。
你说:
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
}
})
你可以在 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()
})