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

mea*_*ers 3 key-value-observing swift swift4

我有:

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

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

是否[weak self]需要在这里?

Jas*_*oss 6

简短答案:是的,您确实需要[weak self]。不必显式删除观察者deinit是一个很好的便利,它确保观察中心不会将通知发送给已取消初始化的观察者,但不会使您不必为关闭操作管理内存。

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

默认情况下,闭包表达式从其周围的范围捕获常量和变量,并强烈引用这些值。您可以使用捕获列表来明确控制如何在闭包中捕获值。

在参数列表之前,捕获列表被写为用逗号括起来的表达式列表,并用方括号括起来。如果使用捕获列表,则即使省略参数名称,参数类型和返回类型,也必须使用in关键字。

....

如果表达式的值的类型是类,则可以在捕获列表中将表达式标记为弱或无主,以捕获对表达式值的弱或无主引用。

摘自:Apple Inc.“ Swift编程语言(Swift 4.0.3)”。iBooks。

如果未self在捕获列表中标记表达式,则将创建一个强引用循环。因为类是引用类型,而闭包是引用类型,所以创建了一个强大的引用周期。当闭包的主体引用一个类的实例时,闭包将创建对该类实例的引用。默认情况下,这是一个强大的参考,除非您使用捕获列表来定义其他类型的参考。官方记录甚至

当您引用闭包中的成员时,Swift要求您编写self.somePropertyor self.someMethod()(而不是just somePropertysomeMethod()self。这可以帮助您记住,可能会self意外捕获。

在您的情况下,您引用的是封闭体内的标签。你需要写的事实

self?.statusLabel.text = viewModel.errorString
Run Code Online (Sandbox Code Playgroud)

而不是简单

.statusLabel.text = viewModel.errorString
Run Code Online (Sandbox Code Playgroud)

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