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:
-
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 -
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) - Deklarowane za pomocą słowa kluczowego
-
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 odniesienieunownedstanie 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. - Deklarowane za pomocą słowa kluczowego
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ćnilpo 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.