Sobes.tech
Middle

Ce tipuri de legături există în Swift?

sobes.tech AI

Răspuns de la AI

În Swift există trei tipuri principale de referințe la instanțele de clasă:

  1. Referință puternică (Strong Reference):

    • Acesta este tipul implicit de referință.
    • O referință puternică crește contorul de referințe al obiectului.
    • Obiectul nu va fi eliberat din memorie atâta timp cât există cel puțin o referință puternică.
    • Principalul motiv pentru scurgerile de memorie în cazul ciclurilor de referință puternice (strong reference cycles).
    class Person {
        let name: String
        init(name: String) { self.name = name }
        deinit { print("\(name) este fiind dezinitializat") }
    }
    
    var reference1: Person? = Person(name: "John")
    // reference1 este acum o referință puternică, contorul de referințe al lui Person crește
    
  2. Referință slabă (Weak Reference):

    • Este declarată cu cuvântul cheie weak.
    • O referință slabă nu crește contorul de referințe al obiectului.
    • Este utilizată pentru a preveni strong reference cycles.
    • Este întotdeauna opțională (Optional), deoarece obiectul la care face referire poate fi dezinitializat în orice moment. La dezinitializare, referința slabă devine automat nil.
    class Apartment {
        let unit: String
        weak var tenant: Person? // Referință slabă
        init(unit: String) { self.unit = unit }
        deinit { print("Apartament \(unit) este fiind dezinitializat") }
    }
    
    var john: Person? = Person(name: "John")
    var unit4A: Apartment? = Apartment(unit: "4A")
    
    john?.apartment = unit4A // Dacă Apartment avea o referință puternică către John
    unit4A?.tenant = john   // Referință slabă
    
    // După ștergerea referințelor puternice, obiectele vor fi dezinitializate
    john = nil
    unit4A = nil
    // Rezultat: "John este fiind dezinitializat", "Apartament 4A este fiind dezinitializat"
    // Dacă tenant ar fi fost o referință puternică, s-ar fi produs o scurgere de memorie (cyclică puternică)
    
  3. Referință neasignată (Unowned Reference):

    • Este declarată cu cuvântul cheie unowned.
    • La fel ca referința slabă, nu crește contorul de referințe al obiectului.
    • Este utilizată pentru a preveni strong reference cycles.
    • Spre deosebire de weak, nu este opțională (Optional) și presupune că obiectul la care face referire va exista pe toată durata "vieții" referinței neasignate.
    • Dacă obiectul la care face referire unowned este dezinitializat înainte ca referința unowned să devină invalidă, va apărea o eroare de execuție (runtime error).
    • Se potrivește situațiilor în care un obiect există întotdeauna atâta timp cât un alt obiect asociat există, dar nu invers (de exemplu, o relație "părinte-copil", unde părintele deține copilul, dar copilul nu deține părintele în mod puternic).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) { self.name = name }
        deinit { print("\(name) este fiind dezinitializat") }
    }
    
    class CreditCard {
        let number: Int
        unowned let customer: Customer // Referință neasignată
    
        init(number: Int, customer: Customer) {
            self.number = number
            self.customer = customer // Atribuirea referinței neasignate în init este sigură
        }
        deinit { print("Card #\(number) este fiind dezinitializat") }
    }
    
    var john: Customer? = Customer(name: "John Doe")
    john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Ștergerea referinței puternice către Customer
    john = nil
    // Rezultat: "John Doe este fiind dezinitializat", "Card #1234567890123456 este fiind dezinitializat"
    // Referința neasignată către customer în CreditCard a fost validă atâta timp cât customer a existat.
    // Dacă CreditCard ar fi trăit mai mult decât Customer și am încerca să accesăm customer prin referința neasignată, s-ar produce o eroare.
    

Diferența cheie între weak și unowned:

  • weak: obiectul poate fi nil. Folosiți-l când durata de viață a obiectelor nu este strict legată (unul poate exista fără celălalt).
  • unowned: obiectul nu poate fi nil după inițializare. Folosiți-l când sunteți sigur că obiectul referit va exista cel puțin până când va exista obiectul care face referire.