Что такое модификатор unowned в Swift и чем он отличается от weak?

Ответ

unowned — это модификатор ссылки в Swift, который, как и weak, не увеличивает счетчик сильных ссылок (retain count), но с критическим отличием: он предполагает, что объект назначения никогда не станет nil в течение времени жизни ссылки. Если объект освобождается, обращение к unowned-ссылке вызывает краш приложения (dangling pointer).

Ключевые отличия от weak:

  • weak ссылки всегда optional (weak var delegate: Delegate?) и автоматически обнуляются (nil).
  • unowned ссылки non-optional (unowned let parent: Parent) и не обнуляются.

Когда использовать unowned:

  • Когда время жизни объекта и ссылки совпадает или объект живет дольше.
  • Для устранения циклов сильных ссылок в отношениях, где один объект логически "владеет" другим (например, родитель-ребенок).

Пример безопасного использования:

class Customer {
    let id: String
    var card: CreditCard?
    init(id: String) { self.id = id }
}

class CreditCard {
    let number: String
    // Карта не может существовать без клиента. Клиент живет дольше.
    unowned let customer: Customer
    init(number: String, customer: Customer) {
        self.number = number
        self.customer = customer
    }
}

var john: Customer? = Customer(id: "12345")
john!.card = CreditCard(number: "1111-2222", customer: john!)
john = nil // Теперь и Customer, и CreditCard освобождены. Обращение к card.customer вызовет краш.

Правило: Используйте unowned только при абсолютной уверенности, что объект не будет освобожден раньше ссылки. В сомнительных случаях предпочитайте weak.

Ответ 18+ 🔞

А, ну это же про unowned, да? Вот эта штука, которая как weak, только с хуёвым характером и без страховки.

Смотри, представь: weak — это как твой друг, который может в любой момент слинять, и ты это знаешь. Поэтому ты к нему обращаешься осторожно, через вопросики (weak var friend: Friend?). А если он свалил, то у тебя в руках просто nil, и приложение не падает, ты просто пожимаешь плечами — «ну, бывает».

А вот unowned — это как твой родной отец, который, по твоей наивной уверенности, никогда в жизни не умрёт. Ты на него ссылаешься напрямую, без всяких вопросиков (unowned let dad: Dad). И всё вроде ок, пока он жив. Но если он таки, прости господи, откинулся — и ты попробуешь к нему обратиться... Пиздец. Краш. Приложение в тапки. Dangling pointer, ёпта. Указатель в никуда, в пустоту, в освобождённую память. В рот меня чих-пых!

Так когда же эту опасную хуйню использовать? Только в одном случае: когда ты на 146% уверен, что объект, на который ссылаешься, живёт столько же или дольше, чем твой текущий объект. Это как отношения «родитель-ребёнок». Ребёнок (карта) не может существовать без родителя (клиента). Родитель создаёт ребёнка и передаёт ему ссылку на себя. Пока жив родитель — жив и ребёнок. Значит, можно смело юзать unowned.

Вот, смотри на этот код, тут всё чётко:

class Customer {
    let id: String
    var card: CreditCard? // У клиента МОЖЕТ быть карта
    init(id: String) { self.id = id }
}

class CreditCard {
    let number: String
    // Карта НЕ МОЖЕТ существовать без клиента. Клиент живет дольше или столько же.
    // Поэтому смело — unowned. Без знаков вопроса.
    unowned let customer: Customer
    init(number: String, customer: Customer) {
        self.number = number
        self.customer = customer // Карта рождается, уже зная своего создателя.
    }
}

// Живёт себе Джон-клиент
var john: Customer? = Customer(id: "12345")
// Он заводит карту и говорит ей: «Я твой отец, вот ссылка на меня, храни её, но сильно не держись (unowned)».
john!.card = CreditCard(number: "1111-2222", customer: john!)

// А теперь представь, что Джон взял и умер (nil).
john = nil
// Всё. И клиент, и его карта освобождаются. Цикла нет, молодцы.
// Но если бы где-то завалялась ещё одна сильная ссылка на карту, и она попробовала бы обратиться к card.customer... Э, сабака сука! Краш! Потому что customer уже в лучшем из миров.

Главное правило, блядь: Если у тебя в голове промелькнула хоть тень сомнения — «а вдруг объект освободится раньше?» — выкинь unowned нахуй и бери weak. Лучше optional, чем краш. Волнение ебать, терпения ноль ебать, когда приложение падает из-за такой ерунды.

А то ведь бывает, мартышлюшка, понаставит unowned везде, где попало, а потом удивление пиздец — «ой, а чё это оно крешится?». Сам от себя охуел.