Sobes.tech
Middle

Jakie rodzaje odwołań istnieją w Swift?

sobes.tech AI

Odpowiedź od AI

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

  1. Silne odniesienie (Strong Reference):

    • To domyślny typ odniesienia.
    • Silne odniesienie zwiększa licznik odniesień obiektu.
    • Obiekt nie zostanie zwolniony z pamięci, dopóki istnieje co najmniej jedno silne odniesienie.
    • Główną przyczyną wycieków pamięci w przypadku cyklicznych silnych odniesień (strong reference cycles).
    class Person {
        let name: String
        init(name: String) { self.name = name }
        deinit { print("\(name) jest wywoływany") }
    }
    
    var reference1: Person? = Person(name: "John")
    // reference1 jest teraz silnym odniesieniem, licznik odniesień Person się zwiększa
    
  2. Słabe odniesienie (Weak Reference):

    • Deklarowane za pomocą słowa kluczowego weak.
    • Słabe odniesienie nie zwiększa licznika odniesień obiektu.
    • Używane do zapobiegania strong reference cycles.
    • Zawsze jest opcjonalne (Optional), ponieważ obiekt, na który wskazuje słabe odniesienie, może zostać zniszczony w dowolnym momencie. Gdy obiekt jest niszczony, słabe odniesienie automatycznie staje się nil.
    class Apartment {
        let unit: String
        weak var tenant: Person? // Słabe odniesienie
        init(unit: String) { self.unit = unit }
        deinit { print("Mieszkanie \(unit) jest wywoływane") }
    }
    
    var john: Person? = Person(name: "John")
    var unit4A: Apartment? = Apartment(unit: "4A")
    
    john?.apartment = unit4A // Gdyby Apartment miał silne odniesienie do Person
    unit4A?.tenant = john   // Słabe odniesienie
    
    // Po usunięciu silnych odniesień obiekty zostaną zniszczone
    john = nil
    unit4A = nil
    // Wyjście: "John jest wywoływany", "Mieszkanie 4A jest wywoływane"
    // Gdyby tenant był silnym odniesieniem, wystąpiłby wyciek pamięci (cykl)
    
  3. Nieposiadane odniesienie (Unowned Reference):

    • Deklarowane za pomocą słowa kluczowego unowned.
    • Podobne do słabego odniesienia, nie zwiększa licznika odniesień obiektu.
    • Używane również do zapobiegania strong reference cycles.
    • W przeciwieństwie do weak, nie jest opcjonalne (Optional) i zakłada, że obiekt, na który wskazuje, będzie istnieć przez cały "okres życia" nieposiadanego odniesienia.
    • Jeśli obiekt, na który wskazuje unowned, zostanie zniszczony przed tym, jak odniesienie unowned stanie się nieprawidłowe, wystąpi błąd wykonania (runtime error).
    • Odpowiednie w sytuacjach, gdy jeden obiekt zawsze istnieje, dopóki istnieje inny powiązany obiekt (np. "rodzic-dziecko", gdzie rodzic posiada dziecko, ale dziecko nie posiada rodzica silnie).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) { self.name = name }
        deinit { print("\(name) jest wywoływany") }
    }
    
    class CreditCard {
        let number: Int
        unowned let customer: Customer // Nieposiadane odniesienie
    
        init(number: Int, customer: Customer) {
            self.number = number
            self.customer = customer // Bezpieczne przypisanie w init
        }
        deinit { print("Karta #\(number) jest wywoływana") }
    }
    
    var john: Customer? = Customer(name: "John Doe")
    john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Usunięcie silnego odniesienia do Customer
    john = nil
    // Wyjście: "John Doe jest wywoływany", "Karta #1234567890123456 jest wywoływana"
    // Nieposiadane odniesienie w CreditCard było ważne, dopóki customer istniał.
    // Jeśli CreditCard żyłby dłużej niż Customer i próbowałby się odwołać do customer przez nieposiadane odniesienie, wystąpiłby błąd.
    

Kluczowa różnica między weak a unowned:

  • weak: obiekt może być nil. Używaj, gdy czas życia obiektów nie jest ściśle powiązany (jeden może istnieć bez drugiego).
  • unowned: obiekt nie może być nil po inicjalizacji. Używaj, gdy jesteś pewien, że obiekt, na który się odwołujesz, będzie istnieć przynajmniej do czasu, gdy istnieje obiekt odwołujący się do niego.