Назад к вопросам
Middle
93
questionbank

Какие виды ссылок существуют в Swift?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

В Swift существуют три основных вида ссылок на экземпляры классов:

  1. Сильная ссылка (Strong Reference):

    • Это тип ссылки по умолчанию.
    • Сильная ссылка увеличивает счетчик ссылок объекта.
    • Объект не будет освобожден из памяти до тех пор, пока на него есть хотя бы одна сильная ссылка.
    • Основная причина утечек памяти в случае циклических сильных ссылок (strong reference cycles).
    class Person {
        let name: String
        init(name: String) { self.name = name }
        deinit { print("\(name) is being deinitialized") }
    }
    
    var reference1: Person? = Person(name: "John")
    // reference1 теперь сильная ссылка, счетчик ссылок Person увеличивается
    
  2. Слабая ссылка (Weak Reference):

    • Объявляется с использованием ключевого слова weak.
    • Слабая ссылка не увеличивает счетчик ссылок объекта.
    • Используется для предотвращения strong reference cycles.
    • Всегда является опциональной (Optional), потому что объект, на который указывает слабая ссылка, может быть деинициализирован в любое время. При деинициализации объекта слабая ссылка автоматически становится nil.
    class Apartment {
        let unit: String
        weak var tenant: Person? // Слабая ссылка
        init(unit: String) { self.unit = unit }
        deinit { print("Apartment \(unit) is being deinitialized") }
    }
    
    var john: Person? = Person(name: "John")
    var unit4A: Apartment? = Apartment(unit: "4A")
    
    john?.apartment = unit4A // Если бы Apartment имел сильную ссылку на Person
    unit4A?.tenant = john   // Слабая ссылка
    
    // После сброса сильных ссылок, объекты будут деинициализированы
    john = nil
    unit4A = nil
    // Вывод: "John is being deinitialized", "Apartment 4A is being deinitialized"
    // Если бы tenant была сильной ссылкой, произошла бы утечка памяти (strong cycle)
    
  3. Бесхозная ссылка (Unowned Reference):

    • Объявляется с использованием ключевого слова unowned.
    • Подобно слабой ссылке, не увеличивает счетчик ссылок объекта.
    • Используется также для предотвращения strong reference cycles.
    • В отличие от weak, не является опциональной (Optional) и предполагает, что объект, на который она указывает, будет существовать в течение всего "срока жизни" бесхозной ссылки.
    • Если объект, на который указывает unowned ссылка, деинициализируется до того, как unowned ссылка станет недействительной, произойдет ошибка выполнения (runtime error).
    • Подходит для ситуаций, когда один объект всегда существует, пока существует другой связанный с ним объект, но не наоборот (например, "родитель-ребенок", где родитель владеет ребенком, но ребенок не владеет родителем сильно).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) { self.name = name }
        deinit { print("\(name) is being deinitialized") }
    }
    
    class CreditCard {
        let number: Int
        unowned let customer: Customer // Бесхозная ссылка
    
        init(number: Int, customer: Customer) {
            self.number = number
            self.customer = customer // Присваивание бесхозной ссылки безопасно в init
        }
        deinit { print("Card #\(number) is being deinitialized") }
    }
    
    var john: Customer? = Customer(name: "John Doe")
    john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Сброс сильной ссылки на Customer
    john = nil
    // Вывод: "John Doe is being deinitialized", "Card #1234567890123456 is being deinitialized"
    // Бесхозная ссылка на customer в CreditCard была действительна, пока customer существовал.
    // Если бы CreditCard жил дольше Customer и мы попытались обратиться к customer через бесхозную ссылку, произошла бы ошибка.
    

Ключевое различие между weak и unowned:

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