Sobes.tech
Middle

Jakie rodzaje referencji istnieją w Swift?

sobes.tech AI

Odpowiedź od AI

W Swift istnieją trzy główne typy odniesień:

  1. **Silne odniesienie (Strong Reference):

    • Zwiększa licznik odniesień do obiektu.
    • Zapobiega deallokacji obiektu tak długo, jak istnieje co najmniej jedno silne odniesienie.
    • Jest domyślnym typem odniesienia w Swift.
    • Główną przyczyną cykli silnych odniesień.
  2. **Słabe odniesienie (Weak Reference):

    • Nie zwiększa licznika odniesień.
    • Pozwala na deallokację obiektu, jeśli nie ma już silnych odniesień.
    • Deklaruje się za pomocą słowa kluczowego weak.
    • Zawsze jest opcjonalne (Optional), ponieważ obiekt, na który się odwołuje, może stać się nil.
    • Używa się go, aby zapobiec cyklom silnych odniesień, gdy jedna instancja może istnieć niezależnie od innej.
    class Person {
        let name: String
        weak var apartment: Apartment? // Słabe odniesienie
        init(name: String) {
            self.name = name
        }
        deinit { print("\(name) deallokowany") }
    }
    
    class Apartment {
        let unit: String
        var tenant: Person? // Normalne silne odniesienie
        init(unit: String) {
            self.unit = unit
        }
        deinit { print("Mieszkanie \(unit) deallokowane") }
    }
    
    var john: Person?
    var unit4A: Apartment?
    
    john = Person(name: "John Appleseed")
    unit4A = Apartment(unit: "4A")
    
    john!.apartment = unit4A
    unit4A!.tenant = john // Tu mógłby powstać cykl silnych odniesień bez weak
    
    // Odwołania są zerowane, obiekty są deallokowane
    john = nil
    unit4A = nil
    
  3. **Odwołanie nieposiadane (Unowned Reference):

    • Nie zwiększa licznika odniesień.
    • Pozwala na deallokację obiektu, jeśli nie ma już silnych odniesień.
    • Deklaruje się za pomocą słowa kluczowego unowned.
    • Nie jest opcjonalne. Zakłada się, że obiekt, na który się odwołuje, zawsze będzie istnieć, dopóki istnieje instancja zawierająca to odwołanie.
    • Użycie odwołania nieposiadanego na obiekcie, który już został deallokowany, spowoduje błąd w czasie wykonywania (crash).
    • Używa się go, aby zapobiec cyklom silnych odniesień, gdy jedna instancja musi zawsze istnieć, dopóki istnieje inna, i nie ma możliwości, aby jeden z nich stał się nil niezależnie od drugiego (np. w zamknięciach self).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) {
            self.name = name
        }
        deinit { print("\(name) deallokowany") }
    }
    
    class CreditCard {
        let number: UInt64
        unowned let customer: Customer // Odwołanie nieposiadane
        init(number: UInt64, customer: Customer) {
            self.number = number
            self.customer = customer
        }
        deinit { print("Karta #\(number) deallokowana") }
    }
    
    var john: Customer? = Customer(name: "John Appleseed")
    john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Jeśli klient zostanie anulowany, karta odwołująca się do niego za pomocą unowned,
    // stanie się nieprawidłowa, ale nie spowoduje cyklu.
    john = nil // Oba obiekty są deallokowane
    

Wybór między weak a unowned zależy od charakteru relacji między obiektami: użyj weak, gdy jeden obiekt może istnieć bez drugiego (Person bez Apartment), i unowned, gdy jeden obiekt zawsze musi istnieć, dopóki istnieje drugi (CreditCard zawsze należy do Customer).