Что такое сильная ссылка в Swift и какие проблемы могут возникнуть при множественных ссылках на объект?

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

Ответ

Сильная ссылка (strong reference) — это ссылка по умолчанию в Swift, которая увеличивает счетчик ссылок (retain count) объекта в куче. Пока существует хотя бы одна сильная ссылка, объект не будет освобожден.

Пример множественных сильных ссылок:

class Person {
    let name: String
    init(name: String) { self.name = name; print("(name) инициализирован") }
    deinit { print("(name) деинициализирован") }
}

var reference1: Person? = Person(name: "Alice") // Retain count = 1
var reference2: Person? = reference1             // Retain count = 2
var reference3: Person? = reference1             // Retain count = 3

reference1 = nil // Retain count = 2
reference2 = nil // Retain count = 1
reference3 = nil // Retain count = 0 -> Срабатывает deinit

Критическая проблема: Циклы сильных ссылок (Strong Reference Cycle) Возникает, когда два объекта ссылаются друг на друга через сильные ссылки, создавая изолированный граф, который никогда не будет освобожден.

class Person {
    let name: String
    var apartment: Apartment? // Сильная ссылка на Apartment
    init(name: String) { self.name = name }
    deinit { print("(name) освобожден") }
}

class Apartment {
    let unit: String
    var tenant: Person? // Сильная ссылка на Person
    init(unit: String) { self.unit = unit }
    deinit { print("Апартаменты (unit) освобождены") }
}

var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john // ЦИКЛ: Person → Apartment → Person

john = nil     // Объект Person НЕ освобождается (retain count = 1)
unit4A = nil   // Объект Apartment НЕ освобождается (retain count = 1)
// ПАМЯТЬ УТЕКАЕТ

Решение: Слабые (weak) и бесхозные (unowned) ссылки

  • weak — не увеличивает retain count. Становится nil, когда объект освобождается.

    class Apartment {
      weak var tenant: Person? // Решение: слабая ссылка
    }
  • unowned — как weak, но предполагает, что объект существует всегда. При обращении к освобожденному объекту — краш.

    class Customer {
      let card: CreditCard
      init(card: CreditCard) { self.card = card }
    }
    
    class CreditCard {
      unowned let customer: Customer // Customer всегда существует дольше
      init(customer: Customer) { self.customer = customer }
    }

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