Ответ
Краш произойдет, если обратиться к unowned ссылке после того, как объект, на который она указывала, был деаллоцирован. 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: "123") // 1. Создаем Customer
john!.card = CreditCard(number: "1111-2222", customer: john!) // 2. Создаем CreditCard
// 3. Customer деаллоцируется досрочно (например, покинул экран)
john = nil
// 4. Позже пытаемся получить доступ к карте (через другой код или глобальную ссылку)
// Если где-то сохранили ссылку на card, то вызов:
// print(card.customer.id) // Fatal error: Attempted to read an unowned reference but object was already deallocated
Почему это происходит:
unownedне является опциональной (unowned?не существует) и не обнуляется автоматически, в отличие отweak.- После
john = nilэкземплярCustomerуничтожается, ноunowned customerвнутриCreditCardпродолжает указывать на освобожденную память. - Следующее обращение к этому месту в памяти вызывает краш.
Когда использовать unowned: Только когда вы абсолютно уверены, что ссылаемый объект переживет ссылающийся (классический пример: делегат, который является родительским контроллером). В остальных случаях безопаснее использовать weak.
Ответ 18+ 🔞
А, ну это же классика, блядь! Сейчас объясню на пальцах, а то некоторые думают, что unowned — это такая бесплатная weak без вопросительных знаков. Хуй там, плавали — знаем!
Смотри, 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
}
}
Всё вроде логично, да? Карта без клиента — хуйня, а не карта. Завязываем её unowned ссылкой на клиента. И в теории-то да, клиент должен жить дольше. Но жизнь, она, сука, сложнее.
Дальше разыгрывается трагедия в трёх актах, блядь:
- Появился Джон:
var john: Customer? = Customer(id: "123"). Живой, здоровый, в памяти. - Дали Джону карту:
john!.card = CreditCard(number: "1111-2222", customer: john!). Карта теперь знает своего хозяина через эту самуюunownedссылку. Всё ок. - А вот и пиздец:
john = nil. Джона — нет. Деаллоцировался, освободил память. А его карта-то где? А хуй её знает! Может, где-то в другом месте её сохранили. Но внутри неёcustomer— это теперь указатель в никуда, в освобождённый кусок памяти. Это как адрес дома, который уже снесли. - Финальный аккорд: Пытаемся где-то потом прочитать
card.customer.id. И тут — BANG!Fatal error: Attempted to read an unowned reference but object was already deallocated. В рот мне чих-пых, приложение накрылось медным тазом.
Вот в чём, блядь, соль! unowned — она не опциональная, её в nil не превратить. Она либо указывает на живой объект, либо ведёт прямиком в краш. weak — та хоть сама в nil превратится и даст тебе спокойно проверить, а unowned — нет, она максималистка, ёпта.
Так когда её, эту стерву, использовать-то? Да только тогда, когда ты на 146% уверен, что объект, на который ссылаешься, переживёт тебя. Классика — это делегат, который является твоим родительским контроллером. Контроллер живёт, пока на экране вьюха, вьюха держит ссылку на делегата-контроллер через unowned. Когда контроллер с экрана уйдёт — и вьюху вместе с собой прихватит, так что обращений после смерти не будет.
А во всех остальных случаях, если есть хоть тень сомнения — бери weak, не еби себе и другим мозг. Безопасность, блядь, прежде всего!