2

Xcode 10.2 (Swift 5)起,作用域defer末尾的语句产生:deinit

作用域结束前的“defer”语句总是立即执行;替换为“do”语句以消除此警告

让我们看一下这个例子:

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

deinit {
    defer { <--- Warning
        foo = bar
    }
}
  • 当然,可以通过将代码从观察者移动到方法并显式调用它来消除此警告,但是……</li>

这个警告有什么意义?defer- 将声明放在 中是否合理deinit(例如,能够触发属性的观察者)

4

1 回答 1

4

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

值得注意的是,defer触发属性观察器的使用有点像 hack,它之所以有效,是因为类型检查器认为它是与deinit主体不同的上下文。您还可以使用闭包表达式实现相同的结果:

  deinit {
    { foo = bar }()
  }

理想情况下,会有某种形式的语法让您告诉 Swift“不要在此处执行直接到存储的访问”,这样就不需要这种变通方法,但目前还没有。

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

class C {
  var bar = ""

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

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

  private func doDeinit() {
    foo = bar
  }

  deinit {
    doDeinit()
  }
}
于 2019-03-27T21:41:07.733 回答