Ответ
По умолчанию — по сильной ссылке (strong reference). Механизм зависит от типа переменной и использования списка захвата (capture list).
-
Reference-типы (классы): Захватываются по сильной ссылке. Это может создать цикл сильных ссылок (retain cycle).
class MyClass { var value = 0 lazy var closure: () -> Void = { print(self.value) // Захват `self` по сильной ссылке! } } -
Value-типы (структуры, перечисления): По умолчанию также захватываются по ссылке на исходный экземпляр. Чтобы захватить копию значения на момент создания замыкания, используйте список захвата:
var number = 42 let closure = { [number] in // Захват КОПИИ значения `number` print(number) } number = 100 closure() // Выведет: 42 -
Управление ссылками для классов: Во избежание циклов используйте в списке захвата
weakилиunowned.let closure = { [weak self] in guard let self = self else { return } self.doSomething() // Безопасная работа с опциональной ссылкой }
Ответ 18+ 🔞
А, слушай, вот этот момент про замыкания — он же, блядь, как мина замедленного действия, если не въехать! Ёпта, народ на этом так обжигается, что потом волосы дыбом встают.
Ну смотри, по дефолту-то всё просто, как три копейки: захватывает по сильной ссылке, по-братски, намертво. Но вся хуйня в том, что механизм-то разный для классов и для структур!
С классами — вот тут пиздец и начинается. Берёт он self в замыкание и держит, как удав кролика. А если этот self сам держит это замыкание как свойство — привет, ёбаный retain cycle, память течёт, приложение падает, и ты потом три ночи дебажишь, че за хуйня.
class MyClass {
var value = 0
lazy var closure: () -> Void = {
print(self.value) // Смотри-ка, блядь! Захватил `self` намертво! Пиздец, Колян, цикл!
}
}
Вот это self.value — оно же из замыкания на self ссылается, а self через lazy var на замыкание. Круг замкнулся, ебать! Мертвая хватка.
А вот со структурами и прочей value-хренью — прикол другой. Они вроде как по значению, но замыкание-то по умолчанию тоже ссылку ловит на тот экземпляр, что снаружи. Хочешь снимок, заморозку на момент создания? Тогда, сука, явно в квадратных скобках указывай!
var number = 42
let closure = { [number] in // Вжух! Захватил КОПИЮ, блядь, как есть, 42!
print(number)
}
number = 100 // Меняй что хошь, похуй.
closure() // Выведет: 42. Потому что мы заморозили старую версию, как мамонта в лёд.
И главный лайфхак для классов, чтобы не было циклов — это, блядь, список захвата (capture list), святое дело! Там weak или unowned юзай.
let closure = { [weak self] in // Ага, слабая ссылка, не держим за яйца!
guard let self = self else { return } // Проверили, жив ли ещё объект, или уже в рай улетел.
self.doSomething() // Теперь безопасно работаем, циклов нет, мать вашу!
}
weak — это типа «если объект ещё есть, ок, если его уже нет — ну и похуй, пропускаем». unowned — это когда ты на 146% уверен, что объект переживёт замыкание, иначе креш, пизда.
Вот и вся магия, ёпта. Запомни: по умолчанию — сильная ссылка, для value-типов лови копию через [переменная], а для классов слабь ссылку, а то накосячишь так, что мало не покажется.