Sobes.tech
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ń:

  1. Strong (Silne): Zwiększa licznik odwołań obiektu. Jest to domyślny typ odwołania.
  2. 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 kluczowego weak.
  3. 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ę nil i 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 kluczowego unowned.

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