В чем разница между weak и unowned ссылками в Swift и когда их использовать
Что проверяют
Понимаете ли вы, как работает подсчёт ссылок и как разрывать циклы. Заодно смотрят, знаете ли цену ошибки: unowned на освобождённом объекте роняет приложение.
Как отвечать
Swift управляет памятью подсчётом ссылок. Сильная ссылка удерживает объект, и два объекта, ссылающиеся друг на друга сильно, не освободятся никогда: это цикл удержания.
Разрывают его слабыми ссылками, и их две:
weak: необязательная ссылка, при освобождении объекта становится nil. Требует опционального типа и проверки.
unowned: необязательности нет, обращение к освобождённому объекту приводит к аварийному завершению.
Выбор простой: если ссылка может пережить объект, нужен weak; если по устройству программы объект гарантированно живёт дольше, допустим unowned.
class ViewModel {
var onUpdate: (() -> Void)?
func load() {
service.fetch { [weak self] result in
guard let self else { return }
self.apply(result)
}
}
}Замыкания захватывают self сильно по умолчанию, поэтому список захвата в асинхронных колбэках это обычная практика, а не микрооптимизация.
Где спотыкаются
Ставят unowned «чтобы не разворачивать опционал» и получают падение при гонке: объект успел освободиться раньше колбэка.
Пишут [weak self] там, где замыкание выполняется синхронно и цикла нет: лишний код без пользы.
Не знают, что делегаты объявляются weak именно поэтому, и что структуры циклов не создают, поскольку копируются по значению.