我有:
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]
吗?
答案 0 :(得分:5)
简短回答:是的,你确实需要[weak self]
。不必在deinit
中显式删除观察者是一个很好的方便,可以确保观察中心不会向去初始化的观察者发送通知,但不能免除你必须为闭包管理内存。
Apple的官方文档(Swift编程语言4.0.3)声明:
默认情况下,闭包表达式从其周围范围捕获常量和变量,并强烈引用这些值。您可以使用捕获列表显式控制在闭包中捕获值的方式。
捕获列表在参数列表之前写为以方括号括起的表达式的逗号分隔列表。如果使用捕获列表,则还必须使用in关键字,即使省略了参数名称,参数类型和返回类型。
...
如果表达式的值的类型是一个类,则可以使用weak或unowned标记捕获列表中的表达式,以捕获对表达式值的弱或无主引用。
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 4.0.3).” iBooks.
如果未在捕获列表中标记表达式self
,则会创建一个强引用循环。创建了一个强引用循环,因为类是引用类型,而闭包是引用类型。当闭包的主体引用类的实例时,闭包创建对类实例的引用。默认情况下,这是一个强引用,除非您使用捕获列表来定义不同类型的引用。官方注意到say:
当你在一个闭包中引用
self.someProperty
的成员时,Swift要求你写self.someMethod()
或someProperty
(而不仅仅是someMethod()
或self
) 。这有助于您记住,可能会意外捕获self
。
在您的情况下,您正在引用封闭体内部的标签。你需要写
的事实self?.statusLabel.text = viewModel.errorString
而不是简单
.statusLabel.text = viewModel.errorString
提示您在捕获列表中使用self
。