Sobes.tech
Middle

Povězte nám o správě paměti v iOS.

sobes.tech AI

Odpověď od AI

iOS používá automatické počítání odkazů (ARC) pro správu paměti. ARC automaticky uvolňuje objekty, jakmile na ně přestanou být odkazy.

Hlavní koncepty:

  • Silné Odkazy: Zvyšují čítač odkazů objektu. Objekt nebude uvolněn, dokud na něj existují silné odkazy.
  • Slabé Odkazy: Nezvyšují čítač odkazů. Používají se k prevenci cyklů silných odkazů. Odkazují na objekt, který může být uvolněn. Pokud je objekt uvolněn, slabý odkaz se stává nil.
  • Nezávislý Odkaz (unowned): Podobně jako slabý, nezvyšuje čítač odkazů. Používá se, když objekt, na který odkazuje, má stejnou nebo delší životnost. Nezávislý odkaz se nestává nil při uvolnění objektu. Přístup k uvolněnému objektu přes nezávislý odkaz způsobí běhovou chybu.

Cykly silných odkazů (Retain Cycles): Vznikají, když dva nebo více objektů mají silné odkazy na sebe navzájem, což brání jejich uvolnění. Řeší se pomocí slabých nebo nezávislých odkazů.

Příklad cyklu silných odkazů a jeho řešení:

class Person {
    let jméno: String
    var byt: Apartment?

    init(jméno: String) {
        self.jméno = jméno
        print("\(jméno) je inicializováno")
    }

    deinit {
        print("\(jméno) je deinitializováno")
    }
}

class Apartment {
    let jednotka: String
    weak var nájemník: Person? // Použití slabého odkazu k prevenci cyklu

    init(jednotka: String) {
        self.jednotka = jednotka
        print("Byt \(jednotka) je inicializován")
    }

    deinit {
        print("Byt \(jednotka) je deinitializován")
    }
}

var john: Person? = Person(jméno: "John Appleseed")
var jednotka4A: Apartment? = Apartment(jednotka: "4A")

john!.byt = jednotka4A
jednotka4A!.nájemník = john // Tady vzniká cyklus

john = nil
jednotka4A = nil
// Metody deinit nejsou volány kvůli cyklu

Řešení pomocí slabého odkazu:

class Person {
    let jméno: String
    var byt: Apartment?

    init(jméno: String) {
        self.jméno = jméno
        print("\(jméno) je inicializováno")
    }

    deinit {
        print("\(jméno) je deinitializováno")
    }
}

class Apartment {
    let jednotka: String
    weak var nájemník: Person? // Použití slabého odkazu

    init(jednotka: String) {
        self.jednotka = jednotka
        print("Byt \(jednotka) je inicializován")
    }

    deinit {
        print("Byt \(jednotka) je deinitializován")
    }
}

var john: Person? = Person(jméno: "John Appleseed")
var jednotka4A: Apartment? = Apartment(jednotka: "4A")

john!.byt = jednotka4A
jednotka4A!.nájemník = john

john = nil
jednotka4A = nil
// Obě objekty jsou správně deinitializovány

Rozdíl mezi unowned a weak:

  • Použij weak, když odkaz může být nil (objekt může být uvolněn jako první).
  • Použij unowned, když odkaz vždy bude mít hodnotu (objekt, na který odkazuje, má stejnou nebo delší životnost).

Closures a cykly odkazů:

Closures mohou zachytit odkazy na objekty, čímž vytvářejí cykly silných odkazů. To se řeší pomocí capture list.

Příklad:

class HTMLElement {
    let jméno: String
    let text: String?

    lazy var asHTML: () -> String = {
        [weak self] in // Zachytit `self` slabě
        guard let self = self else {
            return ""
        }
        var html = "<\(self.jméno)"
        if let text = self.text {
            html += ">\(text)</\(self.jméno)>"
        } else {
            html += " />"
        }
        return html
    }

    init(jméno: String, text: String? = nil) {
        self.jméno = jméno
        self.text = text
    }

    deinit {
        print("\(jméno) je deinitializováno")
    }
}

var odstavec: HTMLElement? = HTMLElement(jméno: "p", text: "hello, world")
print(odstavec!.asHTML())

odstavec = nil
// Objekt je deinitializováno

Ladění problémů s pamětí:

  • Memory Graph Debugger: V Xcode vizualizuje spojení mezi objekty a odhaluje cykly silných odkazů.
  • Instruments (Allocations, Leaks): Nástroje pro sledování alokace a uvolnění paměti, a hledání úniků.