Какие типы ссылок на объекты существуют в Swift и чем они отличаются?

Ответ

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 — и потом сиди, дебажь, почему всё падает, волнение ебать, терпения ноль ебать.