NSKeyValueObservation observe() 闭包中是否需要弱自我?

Is weak self needed in NSKeyValueObservation observe() closure?

我有:

private var statusLabel:   UILabel!
private var errorObserver: NSKeyValueObservation?

self.errorObserver = self.viewModel.observe(\.errorString)
{ [weak self] (viewModel, change) in
    self?.statusLabel.text = viewModel.errorString
}

这里需要[weak self]吗?

简短回答:是的,您确实需要 [weak self]。不必在 deinit 中明确删除观察者是一个很好的便利,它确保观察中心不会向 de-initialized 观察者发送通知,但并不免除您必须为关闭管理内存。

Apple 的官方文档(Swift 编程语言 4.0.3)指出:

By default, a closure expression captures constants and variables from its surrounding scope with strong references to those values. You can use a capture list to explicitly control how values are captured in a closure.

A capture list is written as a comma-separated list of expressions surrounded by square brackets, before the list of parameters. If you use a capture list, you must also use the in keyword, even if you omit the parameter names, parameter types, and return type.

....

If the type of the expression’s value is a class, you can mark the expression in a capture list with weak or unowned to capture a weak or unowned reference to the expression’s value.

Excerpt From: Apple Inc. “The Swift Programming Language (Swift 4.0.3).” iBooks.

如果在捕获列表中不标记表达式self,将创建一个强引用循环。因为classes是引用类型,而闭包是引用类型,所以产生了强引用循环。当闭包的主体引用 class 的实例时,闭包会创建对 class 实例的引用。默认情况下,这是一个强引用,除非您使用捕获列表来定义不同类型的引用。官方注释连 say:

Swift requires you to write self.someProperty or self.someMethod() (rather than just someProperty or someMethod()) whenever you refer to a member of self within a closure. This helps you remember that it’s possible to capture self by accident.

在您的例子中,您引用的是闭包体内的标签。你需要写的事实

self?.statusLabel.text = viewModel.errorString

而不是简单地

.statusLabel.text = viewModel.errorString

提示您在捕获列表中使用 self