Как closure захватывают ссылки на объекты и что происходит без явного capture list в Swift?
Что проверяют
Понимаете ли вы, откуда берутся циклы сильных ссылок, и умеете ли объяснить, когда список захвата действительно нужен.
Как отвечать
Замыкание захватывает переменные из окружения по ссылке и удерживает их сильно, пока живёт само. Если внутри используется self, замыкание удерживает объект целиком, даже когда обращение выглядит безобидно, например title = name.
Отсюда цикл: объект хранит замыкание в свойстве, а замыкание удерживает объект. Ни один не освобождается, память течёт. Классические случаи это обработчики сетевых запросов, таймеры, подписки, кеш колбэков.
Список захвата разрывает цикл:
loader.onFinish = { [weak self] result in
guard let self else { return }
self.render(result)
}weakделает ссылку необязательной и обнуляет её при уничтожении объекта. Основной выбор, когда объект может исчезнуть раньше замыкания;unownedдешевле, но при обращении к уничтоженному объекту приложение падает. Берут, когда точно известно, что объект переживёт замыкание;- захват значения (
[value = someValue]) фиксирует копию на момент создания замыкания, а не текущее значение переменной.
Важная деталь: не всякое замыкание создаёт цикл. Неубегающие замыкания (map, filter, sort) выполняются сразу и ничего не удерживают, поэтому [weak self] там лишний шум. Цикл возможен только у убегающих замыканий, которые сохраняются где-то надолго.
Где спотыкаются
Пишут [weak self] везде подряд, включая мгновенные вызовы, и добавляют лишние проверки.
Забывают, что unowned роняет приложение, и берут его «потому что короче».
Захватывают self неявно через свойство и считают, что цикла нет, раз слова self в коде не видно.