Ответ
Swift (в контексте управления памятью для классов) предоставляет три основных типа ссылок, которые отличаются своим влиянием на счетчик ссылок (Retain Count) и поведением при освобождении объекта.
| Тип ссылки | Влияние на Retain Count | Опциональность | Поведение при освобождении объекта | Типичный use-case |
|---|---|---|---|---|
| Strong | Увеличивает (+1) | Optional/Non-optional | Удерживает объект в памяти. | Стандартная ссылка, владение объектом. |
| Weak | Не увеличивает | Всегда Optional | Автоматически становится nil. |
Для разрыва потенциальных retain cycles (напр., delegate, дочерние ссылки на родителя). |
| Unowned | Не увеличивает | Non-optional | Остается dangling (обращение → краш). | Когда время жизни ссылаемого объекта гарантированно равно или длиннее времени жизни ссылки. |
Примеры и различия:
class Customer {
let name: String
var card: CreditCard? // Сильная ссылка на CreditCard
init(name: String) { self.name = name }
deinit { print("(name) is being deinitialized") }
}
class CreditCard {
let number: String
weak var customer: Customer? // СЛАБАЯ ссылка разрывает цикл
init(number: String, customer: Customer) {
self.number = number
self.customer = customer // Не увеличивает retain count Customer
}
deinit { print("Card #(number) is being deinitialized") }
}
// Использование
var john: Customer? = Customer(name: "John")
john!.card = CreditCard(number: "1234", customer: john!)
john = nil // Customer освобождается, затем CreditCard, т.к. цикл разорван weak-ссылкой.
// Вывод в консоль:
// John is being deinitialized
// Card #1234 is being deinitialized
Unowned (пример с гарантированным временем жизни):
class Department {
let name: String
unowned var manager: Employee // Руководитель не может существовать без отдела
init(name: String, manager: Employee) { ... }
}
Вывод: Используйте weak для безопасного разрыва циклов, unowned — только при абсолютной уверенности в жизненном цикле, чтобы избежать крашей.
Ответ 18+ 🔞
А, ну это ж про эти ваши ссылки в свифте, блядь! Сидишь такой, пишешь код, а тут — бац! — и память не чистится, объекты болтаются как сопли, и приложение твоё, сука, накрывается медным тазом. Весь цирк из-за того, что не разобрался, как эти три штуки работают. Слушай сюда, разжую.
Вот есть у тебя объект, да? И ты на него ссылку держишь. Так вот, ссылки-то бывают разные, как люди в очереди за колбасой: одни прёт напролом, другие слабенькие, а третьи вообще уверены, что их никогда не выкинут, пока они живы. Вот и вся философия, ёпта.
Сильная (strong) — это как баба, которая вцепилась в тебя мёртвой хваткой. Захотел ты объект удалить? А она не отпускает, блядь! Retain Count увеличивает на единичку, и всё, пиши пропало — объект будет висеть в памяти, пока эта тварь его не отпустит. Стандартная история, без неё никуда. Но если таких баб на один объект навешается несколько — он так и сдохнет в памяти, одинокий и никому не нужный. Use-case? Да обычное владение, что тут думать.
Слабая (weak) — это уже похитрее. Она как та тёлка, которая с тобой только пока ты при деньгах. На Retain Count не влияет, то есть не держит объект. А самое главное — когда объект, на который она ссылалась, помирает, она не остаётся с пустыми руками, а становится nil. Умная, сука! Всегда опциональная, потому что может и обнулиться. Зачем? Чтобы эти ебучие retain cycles не возникали. Вот представь: у тебя Customer есть CreditCard, а у CreditCard ссылка на Customer. Если обе strong — они будут держать друг друга до скончания времён, как два алкаша у подъезда. А weak одну сделал — и цикл порвался, красота! Типично для делегатов или когда ребёнок на родителя ссылается.
Бесславная (unowned) — а вот это, блядь, самая опасная тварь. Она тоже не увеличивает счётчик, но при этом не опциональная! И ведёт себя как полная псина: когда объект, на который она ссылалась, умирает, она не становится nil. Нет! Она так и продолжает указывать на то место в памяти, где этот объект когда-то жил. А ты попробуй по этой ссылке обратиться — получишь краш, в рот меня чих-пых! Весь твой код накроется, и будешь сидеть, чесать репу. Использовать её можно только в одном случае: когда ты на 146% уверен, что объект, на который ты ссылаешься, переживёт тебя. Например, отдел и его начальник. Пока отдел существует, начальник при нём. Но если ты ошибёшься — пиши пропало, ёперный театр.
Вот, смотри, как это в коде выглядит, чтобы совсем понятно было. Блоки кода не трогаю, они святые.
class Customer {
let name: String
var card: CreditCard? // Сильная ссылка на CreditCard
init(name: String) { self.name = name }
deinit { print("(name) is being deinitialized") }
}
class CreditCard {
let number: String
weak var customer: Customer? // СЛАБАЯ ссылка разрывает цикл
init(number: String, customer: Customer) {
self.number = number
self.customer = customer // Не увеличивает retain count Customer
}
deinit { print("Card #(number) is being deinitialized") }
}
// Использование
var john: Customer? = Customer(name: "John")
john!.card = CreditCard(number: "1234", customer: john!)
john = nil // Customer освобождается, затем CreditCard, т.к. цикл разорван weak-ссылкой.
// Вывод в консоль:
// John is being deinitialized
// Card #1234 is being deinitialized
Видишь? Сделал ссылку customer слабой — и они оба благополучно сдохли, когда john в nil ушёл. Цикл не образовался. Красота!
А вот Unowned (пример с гарантированным временем жизни):
class Department {
let name: String
unowned var manager: Employee // Руководитель не может существовать без отдела
init(name: String, manager: Employee) { ... }
}
Тут начальник (manager) привязан к отделу жёстко. Пока отдел жив, и начальник на месте. Но если ты отдел удалишь, а потом попробуешь через department.manager к нему обратиться — получишь по ебалу от рантайма, и заслуженно.
Итог, блядь: weak — для безопасности, когда не уверен. unowned — только если ты абсолютный экстрасенс и на 1000% знаешь жизненные циклы. А иначе — сиди на strong да weak, и будет тебе счастье. А то накосячишь с unowned — и потом сиди, дебажь, почему всё падает, волнение ебать, терпения ноль ебать.