В чем разница между захватом переменной в closure и копированием
Что проверяют
Знаете ли вы, что замыкание в Swift по умолчанию захватывает саму переменную, а не её значение, и умеете ли управлять этим через список захвата. Следующий вопрос почти всегда про [weak self] и циклы сильных ссылок.
Как отвечать
Начните с поведения по умолчанию. Замыкание захватывает переменную по ссылке, даже если это Int или структура: оно видит изменения, сделанные после его создания, и может само её менять. Если замыкание переживает функцию (@escaping), такая переменная переезжает в кучу.
Копия появляется, когда вы пишете список захвата:
var count = 0
let byRef = { print(count) }
let byValue = { [count] in print(count) }
count = 5
byRef() // 5
byValue() // 0[count]: значение копируется в момент создания замыкания и становится константой, изменить его внутри нельзя;- ссылочные типы:
[obj]копирует ссылку, а не объект. Замыкание по-прежнему держит объект сильно и видит изменения его свойств; [weak self]и[unowned self]: разрывают цикл, в котором объект хранит замыкание, а замыкание держит объект.weakделаетselfопционалом,unownedпадает при обращении к уже освобождённому объекту;- конкурентность: в Swift 6 обращение к захваченной
varиз@Sendable-замыкания это ошибка компиляции. Список захвата с копией значения часто самый простой способ её убрать.
Где спотыкаются
Думают, что Int и структуры захватываются копией, раз это value-типы. Без списка захвата замыкание работает с исходной переменной, копию делает только [x].
Считают, что [obj] копирует объект. Копируется ссылка, и цикл удержания остаётся, если объект сам хранит это замыкание.
Ставят [weak self] везде подряд, включая неэскейпящие замыкания вроде map и forEach, где цикла быть не может. Код обрастает guard let self без пользы, а на вопрос «зачем здесь weak» ответа нет.