Отложенное заявление в конце deinit выдает предупреждение - PullRequest
2 голосов
/ 28 марта 2019

Поскольку Xcode 10.2 (Swift 5) оператор defer в конце области действия deinit создает:

оператор 'defer' перед концом области всегда выполняется немедленно; замените на выражение do, чтобы отключить это предупреждение

Давайте посмотрим на этот пример:

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

deinit {
    defer { <--- Warning
        foo = bar
    }
}
  • Конечно, можно избавиться от этого предупреждения, переместив код из наблюдателя в метод и вызвав его явно, но ...

Какой смысл этого предупреждения? - Разве не разумно иметь оператор defer в deinit? (например, чтобы иметь возможность вызывать наблюдателей свойств) .

1 Ответ

4 голосов
/ 28 марта 2019

Предупреждение верно в том смысле, что использование 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()
  }
}
...