Sobes.tech
Middle

Opowiedz o zarządzaniu pamięcią w iOS.

sobes.tech AI

Odpowiedź od AI

iOS używa automatycznego zliczania odwołań (ARC) do zarządzania pamięcią. ARC automatycznie zwalnia obiekty, gdy przestają być odwoływane.

Główne koncepcje:

  • Silne odwołanie: Zwiększa licznik odwołań obiektu. Obiekt nie zostanie zwolniony, dopóki istnieją silne odwołania.
  • Słabe odwołanie: Nie zwiększa licznika odwołań. Używane do zapobiegania cyklom silnych odwołań. Odwołuje się do obiektu, który może zostać zwolniony. Jeśli obiekt zostanie zwolniony, słabe odwołanie staje się nil.
  • Nieposiadane odwołanie (unowned): Podobne do słabego, nie zwiększa licznika odwołań. Używane, gdy obiekt, na który się odwołuje, ma taki sam lub dłuższy cykl życia. Nieposiadane odwołanie nie staje się nil po zwolnieniu obiektu. Próba dostępu do zwolnionego obiektu przez nieposiadane odwołanie powoduje błąd wykonania.

Cykle silnych odwołań (Retain Cycles): Powstają, gdy dwa lub więcej obiektów odwołuje się do siebie nawzajem za pomocą silnych odwołań, uniemożliwiając ich zwolnienie. Rozwiązaniem są słabe lub nieposiadane odwołania.

Przykład cyklu silnych odwołań i jego rozwiązanie:

class Person {
    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
    var tenant: Person? // Silne odwołanie powodujące cykl

    init(unit: String) {
        self.unit = unit
        print("Mieszkanie \(unit) jest inicjalizowane")
    }

    deinit {
        print("Mieszkanie \(unit) jest deinitializowane")
    }
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john // Tworzy cykl

john = nil
unit4A = nil
// Metody deinitializacji nie są wywoływane z powodu cyklu

Rozwiązanie z użyciem weak:

class Person {
    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: Person? // Użycie słabego odwołania

    init(unit: String) {
        self.unit = unit
        print("Mieszkanie \(unit) jest inicjalizowane")
    }

    deinit {
        print("Mieszkanie \(unit) jest deinitializowane")
    }
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A = nil
// Oba obiekty są poprawnie deinitializowane

Nieposiadane (unowned) vs Słabe (weak):

  • Używaj weak, gdy odwołanie może stać się nil (obiekt może zostać zwolniony jako pierwszy).
  • Używaj unowned, gdy odwołanie zawsze będzie miało wartość (obiekt, na który się odwołujesz, ma taki sam lub dłuższy cykl życia).

Zamykania (Closures) i cykle odwołań:

Zamykania mogą przechwytywać odwołania do obiektów, tworząc cykle silnych odwołań. Rozwiązuje się to za pomocą listy przechwytywania (capture list).

Przykład:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        [weak self] in // Przechwytywanie słabe self
        guard let self = self else {
            return ""
        }
        var html = "<\(self.name)"
        if let text = self.text {
            html += ">\(text)</\(self.name)>"
        } else {
            html += " />"
        }
        return html
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) jest deinitializowany")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "cześć, świecie")
print(paragraph!.asHTML())

paragraph = nil
// Obiekt jest deinitializowany

Debugowanie problemów z pamięcią:

  • Memory Graph Debugger: W Xcode, pozwala wizualizować powiązania między obiektami i wykrywać cykle silnych odwołań.
  • Instruments (Allocations, Leaks): Narzędzia do monitorowania przydziału i zwalniania pamięci, wykrywania wycieków.