Ответ
Краш произойдет, если обратиться к 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.