Sobes.tech
Middle

Povedzte nám o správe pamäte v iOS.

sobes.tech AI

Odpoveď od AI

iOS používa automatické spravovanie pamäti pomocou ARC (Automatic Reference Counting). ARC automaticky uvoľňuje objekty, keď na ne prestanú byť odkazy.

Hlavné koncepty:

  • Silný odkaz: Zvyšuje počítadlo odkazov na objekt. Objekt nebude uvoľnený, kým na neho existujú silné odkazy.
  • Slabý odkaz: nezvyšuje počítadlo odkazov. Používa sa na zabránenie cyklov silných odkazov. Odkazuje na objekt, ktorý môže byť uvoľnený. Ak je objekt uvoľnený, slabý odkaz sa stáva nil.
  • Neporušený odkaz: Podobne ako slabý, nezvyšuje počítadlo odkazov. Používa sa, keď objekt, na ktorý odkazuje, má rovnaký alebo dlhší životný cyklus. Neporušený odkaz sa nestane nil pri uvoľnení objektu. Pri pokuse o prístup k uvoľnenému objektu cez neporušený odkaz vznikne chyba behu.

Cyklus silných odkazov (Retain Cycles): Vznikajú, keď dva alebo viac objektov má navzájom silné odkazy, čo bráni ich uvoľneniu. Rieši sa to pomocou slabých alebo neporušených odkazov.

Príklad cyklu silných odkazov a jeho riešenie:

class Person {
    let name: String
    var apartment: Apartment?

    init(name: String) {
        self.name = name
        print("\(name) sa inicializuje")
    }

    deinit {
        print("\(name) sa deinitializuje")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Použitie slabého odkazu na zabránenie cyklu

    init(unit: String) {
        self.unit = unit
        print("Apartmán \(unit) sa inicializuje")
    }

    deinit {
        print("Apartmán \(unit) sa deinitializuje")
    }
}

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

john!.apartment = unit4A
unit4A!.tenant = john // Tu vzniká cyklus

john = nil
unit4A = nil
// Metódy deinitializácie nie sú volané kvôli cyklu

Riešenie pomocou weak:

class Person {
    let name: String
    var apartment: Apartment?

    init(name: String) {
        self.name = name
        print("\(name) sa inicializuje")
    }

    deinit {
        print("\(name) sa deinitializuje")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Použitie slabého odkazu na zabránenie cyklu

    init(unit: String) {
        self.unit = unit
        print("Apartmán \(unit) sa inicializuje")
    }

    deinit {
        print("Apartmán \(unit) sa deinitializuje")
    }
}

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

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

john = nil
unit4A = nil
// Obidva objekty sú správne deinitializované

Neporušené vs Slabé:

  • Používaj weak, keď odkaz môže byť nil (objekt môže byť uvoľnený prvý).
  • Používaj unowned, keď odkaz vždy bude mať hodnotu (objekt, na ktorý odkazuje, má rovnaký alebo dlhší životný cyklus).

Closure a cykly odkazov:

Closure môžu zachytávať odkazy na objekty, čím vytvárajú cykly silných odkazov. Rieši sa to pomocou zoznamu zachytávania (capture list).

Príklad:

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

    lazy var asHTML: () -> String = {
        [weak self] in // Zachytávanie `self` slabým odkazom
        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) sa deinitializuje")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "ahoj, svet")
print(paragraph!.asHTML())

paragraph = nil
// Objekt je deinitializovaný

Ladenie problémov s pamäťou:

  • Memory Graph Debugger: V Xcode umožňuje vizualizovať väzby medzi objektmi a odhaľovať cykly silných odkazov.
  • Instruments (Allocations, Leaks): Nástroje na sledovanie alokácie a uvoľňovania pamäti, hľadanie únikov pamäti.