Я экспериментировал со следующим кодом в Xcode Playground:
class X {
var a = 3
init(a: Int) {
self.a = a
}
deinit {
print("\(self.a) is deallocated.")
}
func returnX() -> Int {
return self.a
}
lazy var anotherReturnX: () -> Int = {
return self.a
}
}
var e: X? = X(a: 6)
print(e!.returnX())
e = nil // prints "6 is deallocated."
var f: X? = X(a: 7)
print(f!.anotherReturnX())
f = nil // prints nothing
Из приведенного выше кода я вижу, что в функции returnX()
нет ссылки, поэтому e
освобождается один разЯ установил e
на nil
.Однако ссылка сохраняется в закрытии anotherReturnX()
, поэтому f
не освобождается.По-видимому, это подразумевает, что замыкание захватывает ссылки, а функция - нет.
Кроме того, когда я впервые набирал код, я не включал ключевое слово lazy
перед объявлением замыкания, как я думал, что это будетбыть ненужным, чтобы сделать это.Однако это вызывает ошибку во время компиляции.Я предполагаю, что, поскольку к замыканию можно получить доступ только после создания экземпляра, он должен получить доступ к созданному экземпляру self
.Но поскольку то, что я здесь заявляю, фактически является «анонимной функцией», зачем вообще закрытому доступу к self
во время создания экземпляра?
После некоторых размышлений я обнаружил больше противоречий.Например, я понимаю, что ссылка захватывается при вызове замыкания.Однако во время инициализации X
я просто назначаю закрытие переменной , не вызывая ее , так же, как объявление других свойств экземпляра.Таким образом, закрытие не должно ничего делать во время инициализации, и компиляция кода без ключевого слова lazy
должна быть в порядке.Но компиляция не удалась.Я не уверен, что идет не так в моем понимании.
Я прочитал некоторые связанные статьи, такие как сильная / слабая ссылка, сохранить цикл, ленивое хранимое свойство.Однако многие объясняют «что происходит» и мало говорят о «почему».
Итак, помимо вопроса, поднятого в заголовке, я также хотел бы уточнить, что отличает функцию и замыкание от других, так что возникает описанная выше ситуация?
Обновление:
Тот факт, что замыкание захватывает ссылку, в то время как функция не применяется, еще больше "навязывается" мне, поскольку, согласно компилятору Xcode, я могу переписать return self.a
как return a
в returnX()
, но я не могу сделать это вanotherReturnX
.Таким образом, я полагаю, я должен был бы согласиться с тем, что, хотя функция и замыкание схожи, поскольку каждая из них является «набором функциональных возможностей», функция отличается от замыкания тем, что она не захватывает ссылки.Если бы я углубился в причину этого, это, вероятно, потребовало бы разработки самого Swift?
Однако я все еще не могу понять, почему ключевое слово lazy
требуется для объявления закрытия.