Что такое closure и capture list в Swift и как они работают
Что проверяют
Понимаете ли вы, что замыкание захватывает переменные по ссылке и держит объекты сильно, и можете ли по коду сказать, будет ли утечка. Следом обычно показывают фрагмент с [weak self] и спрашивают, нужен ли он здесь, а потом про разницу weak и unowned.
Как отвечать
Замыкание в Swift это функция вместе с захваченным окружением, и оно ссылочного типа.
По умолчанию захват устроен так:
- переменные захватываются по ссылке: замыкание видит саму переменную, а не копию. Если после создания замыкания изменить
counter, при вызове оно увидит новое значение; - объекты удерживаются сильно: пока живо замыкание, жив и захваченный объект, включая
self.
Capture list в квадратных скобках фиксирует захват в момент создания замыкания:
[x]: значение копируется сразу, дальнейшие изменения переменной замыкание не увидит;[weak self]: слабая ссылка, внутриselfопционален. Со Swift 5.7 работает короткоеguard let self else { return }, а со Swift 5.8 после такой проверки можно не писатьself.;[unowned self]: без удержания и без опционала, но обращение после освобождения объекта роняет приложение. Годится, только если замыкание гарантированно не переживёт владельца.
Цикл возникает, когда объект хранит замыкание (в свойстве-колбэке, в подписке Combine через sink), а замыкание сильно держит этот объект. Передача замыкания в UIView.animate или DispatchQueue.main.async цикла не создаёт: оно выполнится и освободится, объект просто проживёт чуть дольше.
Упомяните @escaping: по умолчанию параметр-замыкание неубегающее: вызывается до возврата из функции, неявный self в нём разрешён. Убегающее может жить сколько угодно, и вопрос удержания становится реальным.
Где спотыкаются
Ставят [weak self] механически, включая замыкания, которые вызываются сразу и нигде не хранятся. Ошибки нет, но видно, что кандидат не понимает, где цикл.
Выбирают unowned ради отсутствия опционала там, где объект может уйти раньше. Итог: плавающее падение в продакшене.
В Task с долгой работой пишут guard let self в первой строке. Сильная ссылка живёт до конца задачи, и слабый захват ничего не дал.