Для чего используется unowned ссылка в Swift и чем она отличается от weak?

Ответ

unowned — это ссылка, которая не увеличивает счетчик ссылок, но предполагается, что объект, на который она ссылается, не будет деаллоцирован в течение всего времени жизни ссылки. Обращение к unowned ссылке после деаллокации объекта вызывает краш (небезопасное разыменование).

Отличие от weak: weak unowned
Автоматически становится nil при деаллокации объекта. Не становится nil. Приводит к крашу при обращении к деаллоцированному объекту.
Всегда объявляется как var и имеет опциональный тип (T?). Может быть let и имеет неопциональный тип (T).
Используется, когда ссылка может стать nil в будущем. Используется, когда время жизни объектов жестко связано, и ссылка никогда не переживет объект.

Пример (классический retain cycle между Parent и Child):

class Parent {
    var child: Child?
}

class Child {
    // Child не может существовать без Parent, поэтому parent — unowned.
    unowned let parent: Parent
    init(parent: Parent) {
        self.parent = parent
    }
}

var parent: Parent? = Parent()
parent?.child = Child(parent: parent!)
// Нет цикла сильных ссылок: Parent -> Child (strong), Child -> Parent (unowned).
parent = nil // Все объекты корректно деаллоцируются.
// Если бы мы потом попытались обратиться к child.parent — был бы краш, но child тоже уничтожен.

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

Ответ 18+ 🔞

Давай разберём эту штуку, а то в документации написано как для роботов, а на деле всё проще, хоть и с подводными граблями.

Вот представь: unowned — это как твой друг, который занял у тебя сотку и говорит: «Не волнуйся, отдам точно завтра!». Ты ему веришь, счётчик долгов не увеличиваешь, но если он свалит в закат, а ты припёрся за деньгами — будет пиздец, краш и разборки. Ссылка есть, а объекта уже нет.

А weak — это уже более хитрая жопа. Это как знакомый, который тоже занял, но ты ему не доверяешь до конца. Ты мысленно уже списал эти деньги (nil), и если он исчезнет — ну и хуй с ним, не удивишься. Ты просто проверишь кошелёк — пусто? Значит, сдох. Никакого краша.

Короче, таблица, чтобы не ебать мозг:

weak (слабак) unowned (наглец)
Становится nil, если объект умер. Не становится nil. Умрёт объект — попробуй ткнись, получишь краш в ебало.
Всегда var и опциональный тип (T?). Может быть let, тип неопциональный (T). Как будто объект точно есть.
Используй, когда ссылка вдруг может испариться. Используй, когда объекты жёстко сцеплены по жизни. Как родитель и ребёнок — ребёнок без родителя просто немыслим.

Пример из жизни, чтобы вообще всё встало на свои места:

Допустим, есть класс Родитель и класс Ребёнок. Ребёнок без родителя — это нонсенс, абсурд, пиздец. Значит, ссылку на родителя в ребёнке можно смело делать unowned. Родитель умрёт — ребёнка вообще не должно существовать, так что и обращаться к ссылке будет некому.

class Родитель {
    var ребёнок: Ребёнок?
}

class Ребёнок {
    // Ребёнок не может жить дольше родителя. Это аксиома, ёпта.
    unowned let родитель: Родитель
    init(родитель: Родитель) {
        self.родитель = родитель
    }
}

var папа: Родитель? = Родитель()
папа?.ребёнок = Ребёнок(родитель: папа!)
// Всё чисто: Родитель -> Ребёнок (сильная ссылка), Ребёнок -> Родитель (unowned, не увеличивает счётчик).
папа = nil // Всё, оба объекта летят в тартарары, как и должно быть.
// Если бы где-то завалялся живой Ребёнок и он попробовал позвать `родитель` — был бы краш. Но его нет, и слава богу.

Итог: unowned — это для уверенных в себе. Когда ты на 146% уверен, что объект, на который ссылаешься, переживёт тебя самого. Если есть хотя бы тень сомнения — бери weak, не рискуй. А то потом будешь сидеть и дебажить краш с разыменованием хуй пойми чего, а время-то, блядь, идёт.