Это в основном связано с подсчетом ссылок . На любой экземпляр, который используется внутри замыкания (но был объявлен снаружи), имеются жесткие ссылки (т.е. его счетчик ссылок увеличивается). Это может привести к сохранению циклов, например
class MyClass {
var myClosure: (() -> Void)!
init() {
myClosure = {
self.foo()
}
}
func foo() {
}
}
В приведенном выше примере экземпляр MyClass
сохраняет ссылку на myClosure
и наоборот, что означает, что экземпляр MyClass
останется в памяти навсегда.
Вы также можете иметь более сложные / трудные для хранения циклы хранения, поэтому вам нужно действительно обратить внимание и, если у вас возникнут какие-либо сомнения, добавить несколько print
вызовов в класс * deinit
методов вашего класса, чтобы убедиться, что (или используйте инструменты).
Чтобы избежать этих проблем, вы можете пометить объекты, захваченные в замыканиях, как unowned
или weak
. Это означает, что их счетчик ссылок не будет увеличен, и вы можете избежать этих циклов сохранения. Приведенный выше пример можно было бы сделать так:
myClosure = { [weak self] in
self?.foo()
}
или, что еще лучше для этого примера, так:
myClosure = { [unowned self] in
self.foo()
}
Хотя первый способ всегда безопасен и то, что вы будете делать с большей вероятностью, версию unowned
легко рассуждать в этом примере, поскольку вы знаете, что myClosure
не переживет self
. Однако, если вы не уверены на 100%, что self
всегда переживет закрытие, используйте weak
.
Также обратите внимание, что вы можете пометить, как захватывать несколько объектов, используемых внутри замыкания, просто разделив их запятыми, например,
myClosure = { [weak self, unowned bar] in
self?.foo(bar)
}