deinit 末尾的 Defer 语句会产生警告

Defer statement at the end of deinit produces a warning

因为 Xcode 10.2 (Swift 5) defer 声明在deinit 范围的末尾产生:

'defer' statement before end of scope always executes immediately; replace with 'do' statement to silence this warning

我们来看这个例子:

var foo: String {
    didSet {
        // smt
    }
}

deinit {
    defer { <--- Warning
        foo = bar
    }
}

这个警告有什么意义? - deinit 中的 defer 语句是否合理? (例如能够触发属性的观察者).

警告是正确的,因为在此处使用 defer 不会更改程序的执行顺序,而这正是该语句的设计目的。然而不幸的是,建议的替换会改变您程序的行为(提交错误:SR-10207)。

值得注意的是,使用 defer 来触发 属性 观察器有点像 hack,它之所以起作用,是因为类型检查器认为它是与 deinit body。您也可以使用闭包表达式实现相同的结果:

  deinit {
    { foo = bar }()
  }

理想情况下,会有某种形式的语法可以让您告诉 Swift "don't perform a direct-to-storage access here",这样就不需要这样的解决方法,但目前没有。

一个不那么棘手的解决方法是将所需的反初始化器逻辑提取到一个单独的方法中,该方法将逻辑置于 属性 访问正常完成的上下文中:

class C {
  var bar = ""

  var foo: String {
    didSet {
      // smt
    }
  }

  init(foo: String) { self.foo = foo }

  private func doDeinit() {
    foo = bar
  }

  deinit {
    doDeinit()
  }
}