В каком случае обращение к `unowned` ссылке в Swift приведет к крашу приложения?

«В каком случае обращение к `unowned` ссылке в Swift приведет к крашу приложения?» — вопрос из категории Управление памятью, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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