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á
nilpř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ýtnil(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ů.