Middle
Papaskinkite apie atminties valdymą iOS.
sobes.tech AI
Atsakymas iš AI
iOS naudoja automatinį atminties valdymą per ARC (Automatic Reference Counting). ARC automatiškai atlaisvina objektus, kai jiems nebėra nuorodų:
Pagrindinės sąvokos:
- Stipri nuoroda: Padidina nuorodų skaitiklį objekto. Objekto nebus atlaisvinta, kol yra stiprių nuorodų.
- Silpna nuoroda: Nepadidina nuorodų skaitiklio. Naudojama stiprių nuorodų ciklų prevencijai. Nuoroda į objektą, kuris gali būti atlaisvintas. Jei objektas atlaisvinamas, silpna nuoroda tampa
nil. - Nepakeičiama nuoroda: Panaši į silpną, bet nepasidaro
nilobjekto atlaisvinimo metu. Naudojama, kai objektas turi tą patį arba ilgesnį gyvavimo ciklą. Nepakeičiama nuoroda nepasidaronilatlaisvinus objektą. Bandant pasiekti atlaisvintą objektą per nepakeičiamą nuorodą, įvyksta klaida.
Stiprių nuorodų ciklai (Retain Cycles): atsiranda, kai du ar daugiau objektų turi stiprių nuorodų vienas į kitą, neleidžiančių jiems būti atlaisvintiems. Sprendžiama naudojant silpnus arba nepakeičiamus nuorodų tipus.
Pavyzdys:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) pradeda kurti")
}
deinit {
print("\(name) baigia")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Naudojama silpna nuoroda, kad išvengtume ciklo
init(unit: String) {
self.unit = unit
print("Apartment \(unit) pradeda kurti")
}
deinit {
print("Apartment \(unit) baigia")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john // Čia susidaro ciklas
john = nil
unit4A = nil
// Deinitializacijos metodai neiškviečiami dėl ciklo
Sprendimas naudojant weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) pradeda kurti")
}
deinit {
print("\(name) baigia")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Naudojama silpna nuoroda, kad išvengtume ciklo
init(unit: String) {
self.unit = unit
print("Apartment \(unit) pradeda kurti")
}
deinit {
print("Apartment \(unit) baigia")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil
// Abu objektai teisingai išvalomi
Nepakeičiama vs Silpna:
- Naudok
weak, kai nuoroda gali taptinil(objektas gali būti pirmas atlaisvintas) - Naudok
unowned, kai nuoroda visada turės reikšmę (objektas, į kurį nuoroda, turi tą patį arba ilgesnį gyvavimo ciklą)
Uždarymai (Closures) ir ciklai:
Uždarymai gali įsikibti į objektų nuorodas, sukurdami stiprius ciklus. Tai sprendžiama naudojant capture list.
Pavyzdys:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[weak self] in // įkibti į `self` silpna nuoroda
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) baigia")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "labas, pasauli")
print(paragraph!.asHTML())
paragraph = nil
// Objektas išvalytas
Atminties problemų derinimas:
- Memory Graph Debugger: Xcode leidžia vizualizuoti objektų ryšius ir aptikti ciklus
- Instruments (Allocations, Leaks): Stebi atminties paskirstymą ir išlaisvinimą, ieško nutekėjimų.