Прочитав некоторые статьи и руководство разработчика Apple, я все еще не понимаю, что в конце Capture List. Что означает «захват», как это работает за кадром с точки зрения бесхозяйного и слабого «я»? как закрытие использует себя, не владея объектом? Я думал, что это похоже на создание копии этого объекта, поэтому, когда он будет закончен, он будет передан из стека как тип значения, но я думаю, что я ошибаюсь. Я надеюсь, что кто-то из присутствующих может сделать это более простым и понятным для понимания или связал меня с хорошей статьей, отвечающей на этот конкретный вопрос. Спасибо за аванс
Я понимаю, и это может быть немного упрощено, что речь идет о владении и удержании объекта, что означает, что пока мы заявляем о праве собственности на объект, он не может быть освобожден из памяти, даже другая часть кода устанавливает его до нуля или аналогичного.
В случае weak
мы говорим, что уничтожить объект - это нормально, и что мы будем использовать его только в том случае, если он все еще рядом.
Поэтому, объявляя self
как weak
в закрытии, мы говорим, что если self
все еще существует, когда пришло время выполнить закрытие, мы делаем это обычно, иначе закрытие будет игнорироваться без генерации ошибки.
В основном это связано с подсчет ссылок. Любой экземпляр, который используется внутри замыкания (но был объявлен снаружи), имеет сильную ссылку (т.е. его счетчик ссылок увеличивается). Это может привести к сохранению циклов, например
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)
}
Если мы будем иметь в виду, что захваченные значения по умолчанию являются сильными ссылками в замыканиях, мы можем предположить, что это может создать циклы сохранения (плохие вещи).
список захвата - это массив переменных, которые вы можете передать в замыкание. Назначение списков захвата - изменить силу передаваемых переменных. Это используется для прерывания циклов сохранения.
Например:
// strong reference
[label = self.myLabel!] in
// weak reference
[weak label = self.myLabel!] in
// unowned reference
[unowned self] in
«иначе закрытие будет игнорироваться без выдачи ошибки». Закрытие не будет «проигнорировано». Закрытие выполняется, как и в противном случае. Если объект, на который указывает ссылка, замыкание, захваченное как
weak
, уже деинициализировано при запуске замыкания, ссылка будет иметь значениеnil
внутри замыкания.