什么时候我们不应该使用 [weak self] 和 [unowned self]?

When we should NOT use neither [weak self] nor [unowned self]?

我在 Whosebug 上阅读了一些关于何时应该在闭包中使用 [weak self] [unowned self] 的讨论。

但是,是否存在我们不必使用其中一个 的情况,因为 Swift 在我们使用时不会显示任何错误或警告只是在闭包中显式使用 self

比如这里应该用weak还是unowned

UIView.animate(withDuration: 0.3) {
    self.view.alpha = 0.0
}

这有点基于意见,所以我会给出我的意见:)

我通常基于同步性。如果一个闭包是 Async 的,当关闭器被调用时,调用实例可能不再存在,因此应该使用 [weak self]。如果一个闭包是同步的,那么它是不必要的并且捕获一个强引用就可以了。

可以 扩展为还包括闭包,您可以合理地期望您的实例在被调用时保持有效(例如,您的视图动画案例),但是请注意,这会使假设闭包和您对它的使用将保持不变,因此理论上它可能会在将来的某个时候中断。这不太安全,并且使未来的维护更多 difficult/dangerous。

对于像 UIView.animate 这样的既定且可预测的 API,为了简洁起见,我个人倾向于使用 strong self,但这是您需要自己进行的评估,并且这取决于使用情况。

另外如评论中所述,函数闭包也是如此。将闭包分配给另一个变量的 属性 有一组不同的问题。

顺便说一句,我采用了弱引用闭包的方法,只是在我的类型中调用另一个方法,例如

thing.doSomethingWithAClosure() { [weak self]
    self?.doSomething()
}

它简化了逻辑,同时还执行了更多 functional/modular 代码。

如果你的闭包会导致强引用循环,你需要使用 [weak self] 或 [unowned self]。

如果您将闭包分配给self的属性并且您引用selfself inside 闭包本身的 属性。闭包是引用类型,因此基本上相同的规则适用于强引用,就像您使用普通 classes.

对于您的示例,不需要 [weak self][unowned self],因为您没有将闭包分配给 class 中的变量,[=14] =]引用,所以不会有强引用循环。

有关详细信息,请查看 Swift 编程语言指南的 Strong Reference Cycles for Closures 部分。以下是上述 link 中闭包导致强引用循环的示例:

class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

asHTML的闭包中没有[unowned self],赋值给asHTML的闭包会造成强引用循环。将 asHTML 的实现更改为以下内容可解决此问题:

lazy var asHTML: () -> String = {
    [unowned self] in
    if let text = self.text {
        return "<\(self.name)>\(text)</\(self.name)>"
    } else {
        return "<\(self.name) />"
    }
}