Swift - Самостоятельное разъяснение списка захвата

Прочитав некоторые статьи и руководство для разработчиков Apple, я все еще не понимаю, что такое Capture List в заключении. Что означает «захват», как это работает за кулисами с точки зрения бесхозяйного «я» и слабого «я»? как закрытие использует себя, не владея объектом? Я думал, что это похоже на создание копии этого объекта, поэтому, когда он будет завершен, он будет передан из стека как тип значения, но я думаю, что ошибаюсь. Я надеюсь, что кто-то здесь может сделать его более простым и понятным для понимания или связал меня с хорошей статьей, отвечающей на этот конкретный вопрос. Спасибо за аванс


person r.pul    schedule 02.05.2018    source источник


Ответы (3)


Мое понимание, и это может быть немного упрощено, заключается в том, что речь идет о владении и удержании объекта, а это означает, что пока мы заявляем о владении объектом, он не может быть освобожден из памяти, даже другая часть кода устанавливает его. до нуля или аналогичный.

С помощью weak мы говорим, что можно уничтожить объект и что мы будем использовать его только в том случае, если он все еще существует.

Поэтому, объявляя self как weak в замыкании, мы говорим, что если self все еще существует, когда пришло время выполнить замыкание, мы делаем это как обычно, иначе замыкание будет молча игнорироваться без генерации ошибки.

person Joakim Danielson    schedule 02.05.2018
comment
в противном случае замыкание будет молча игнорироваться без возникновения ошибки. Закрытие не будет проигнорировано. Закрытие выполняется так же, как и в противном случае. Если объект, на который указывает ссылка, замыкание, захваченное как weak, уже было деинициализировано при запуске замыкания, ссылка будет иметь значение nil внутри замыкания. - person user102008; 16.09.2020

В основном это связано с подсчетом ссылок. Любой экземпляр, который используется внутри замыкания (но был объявлен снаружи), строго ссылается (т. е. его счетчик ссылок увеличивается). Это может привести к сохранению циклов, например.

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)
}
person Guy Kogus    schedule 02.05.2018

Если мы будем помнить, что захваченные значения по умолчанию являются сильными ссылками в замыканиях, мы можем предположить, что это может создавать циклы сохранения (плохие вещи).

Список захвата — это массив переменных, которые вы можете передать в замыкание. Целью списков захвата является изменение силы передаваемых переменных. Это используется для прерывания циклов сохранения.

Например:

// strong reference
[label = self.myLabel!] in

// weak reference
[weak label = self.myLabel!] in

// unowned reference
[unowned self] in
person FranicevicNikola    schedule 16.09.2020