Middle
Czym jest automatyczne liczenie linków?
sobes.tech AI
Odpowiedź od AI
Automatyczne zliczanie odwołań (Automatic Reference Counting, ARC) to mechanizm zarządzania pamięcią w Swift i Objective-C, który automatycznie śledzi i zwalnia pamięć przydzieloną obiektom. Każda instancja klasy ma licznik odwołań, który zwiększa się przy tworzeniu silnego odwołania do obiektu i zmniejsza się przy jego usunięciu. Gdy licznik odwołań osiąga zero, ARC automatycznie deallokuje obiekt i zwalnia zajmowaną przez niego pamięć.
ARC zapobiega wyciekom pamięci i podwójnemu zwalnianiu, upraszczając zarządzanie pamięcią w porównaniu do ręcznego zarządzania (np. w Objective-C bez ARC).
Istnieją trzy typy odwołań:
- Strong (Silne): Zwiększa licznik odwołań obiektu. Jest to domyślny typ odwołania.
- Weak (Słabe): Nie zwiększa licznika odwołań. Używa się go do zapobiegania cyklom silnych odwołań, gdy dwa obiekty odwołują się do siebie nawzajem. Słabe odwołanie staje się
nil, jeśli obiekt, na który wskazuje, zostanie deallokowany. Definiuje się je za pomocą słowa kluczowegoweak. - Unowned (Bez właściciela): Nie zwiększa licznika odwołań i zawsze ma wartość. Używa się go, gdy wiadomo, że odwołanie zawsze będzie wskazywać na obiekt, dopóki obiekt ten istnieje. W przeciwieństwie do
weak, odwołanie bez właściciela nie staje sięnili może spowodować błąd, jeśli spróbuje się uzyskać dostęp do obiektu po jego deallokacji. Definiuje się je za pomocą słowa kluczowegounowned.
Przykład cyklu silnych odwołań:
class Human {
let name: String
var apartment: Apartment? // Silne odwołanie do opcjonalnego Apartment
init(name: String) {
self.name = name
print("\(name) jest inicjalizowany")
}
deinit {
print("\(name) jest deinitializowany")
}
}
class Apartment {
let unit: String
var tenant: Human? // Silne odwołanie do opcjonalnego Human
init(unit: String) {
self.unit = unit
print("Mieszkanie \(unit) jest inicjalizowane")
}
deinit {
print("Mieszkanie \(unit) jest deinitializowane")
}
}
var john: Human?
var unit4A: Apartment?
john = Human(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil
// Nie zostanie wyświetlony żaden komunikat "John Appleseed jest deinitializowany" ani "Mieszkanie 4A jest deinitializowane" z powodu cyklu silnych odwołań
Rozwiązanie problemu cyklu silnych odwołań z użyciem weak:
class Human {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) jest inicjalizowany")
}
deinit {
print("\(name) jest deinitializowany")
}
}
class Apartment {
let unit: String
weak var tenant: Human? // Słabe odwołanie
init(unit: String) {
self.unit = unit
print("Mieszkanie \(unit) jest inicjalizowane")
}
deinit {
print("Mieszkanie \(unit) jest deinitializowane")
}
}
var john: Human?
var unit4A: Apartment?
john = Human(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // John jest deallokowany, ponieważ jego licznik odwołań osiąga 0
unit4A = nil // Mieszkanie jest deallokowane, ponieważ jego licznik odwołań osiąga 0