Как замыкания захватывают значения в Swift
Вопрос
Расскажите, как замыкания захватывают переменные и какие проблемы это создаёт.
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
По умолчанию захват переменной (ссылка на бокс), видно последнее значение
Список захвата `[x]` копирует значение в момент создания
Захват `self` класса сильный: риск цикла ссылок в escaping-замыкании
`[weak self]` и `guard let self`, `[unowned self]` только при гарантии жизни
Non-escaping по умолчанию, escaping при сохранении или асинхронности
Замыкания ссылочные: копия делит захваченное состояние
Что могут спросить следом
- Почему в классе нужно писать
self.в escaping-замыкании? - Нужен ли
[weak self]вUIView.animate?
Разбор
Замыкание захватывает переменные из окружения по ссылке: переменная переносится в бокс в куче, и замыкание видит её актуальное значение, может её менять. Если нужно зафиксировать значение, использую список захвата [x]: тогда в замыкании копия на момент создания. Главная практическая проблема это self. Если объект хранит escaping-замыкание, а замыкание сильно захватывает объект, получается цикл, и ARC их не освободит. Поэтому в completion-обработчиках и подписках пишу [weak self] и guard let self else { return }. unowned беру, только если объект точно живёт дольше. В non-escaping замыканиях вроде map или UIView.animate цикла нет: замыкание не хранится, weak там не нужен. И помню, что сами замыкания ссылочные: присвоил второй константе, и состояние общее.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.