自 Xcode 10.2(Swift 5( 以来,deinit
范围末尾的 defer
语句生成:
作用域结束前的"defer"语句始终会立即执行;用"do"语句替换以消除此警告
让我们看一下这个例子:
var foo: String {
didSet {
// smt
}
}
deinit {
defer { <--- Warning
foo = bar
}
}
- 当然,可以通过将代码从观察者移动到方法并显式调用它来摆脱此警告,但是...
这个警告有什么意义? - 在deinit
中有defer
声明不合理吗?(例如,能够触发属性的观察者(。
警告是正确的,因为在此处使用 defer
不会更改程序的执行顺序,而这正是该语句的设计目的。然而,不幸的是,建议的替换会以其他方式改变程序的行为(提交错误:SR-10207(。
值得注意的是,使用 defer
来触发属性观察器是一种黑客攻击,它只有效,因为类型检查器认为它是与deinit
体不同的上下文。您也可以使用闭包表达式获得相同的结果:
deinit {
{ foo = bar }()
}
理想情况下,会有某种形式的语法可以让你告诉 Swift"不要在这里执行直接到存储的访问",这样这样的解决方法就没有必要了,但目前还没有。
一个不太笨拙的解决方法是将取消初始化器的所需逻辑拉到一个单独的方法中,该方法将逻辑放在属性访问正常完成的上下文中:
class C {
var bar = ""
var foo: String {
didSet {
// smt
}
}
init(foo: String) { self.foo = foo }
private func doDeinit() {
foo = bar
}
deinit {
doDeinit()
}
}