Middle
Vertel ons over het geheugenbeheer in iOS.
sobes.tech AI
Antwoord van AI
iOS gebruikt automatische referentietelling (ARC) voor geheugenbeheer. ARC vrijwaart automatisch objecten zodra er geen referenties meer naar hen zijn.
Belangrijke concepten:
- Strong Reference: Verhoogt de referentieteller van een object. Het object wordt niet vrijgegeven zolang er sterke referenties naar zijn.
- Weak Reference: Verhoogt de teller niet. Gebruikt om cycli van sterke referenties te voorkomen. Verwijst naar een object dat vrijgegeven kan worden. Als het object wordt vrijgegeven, wordt de weak referentie
nil. - Unowned Reference: Vergelijkbaar met weak, verhoogt de teller niet. Gebruikt wanneer het object waarnaar wordt verwezen dezelfde of een langere levensduur heeft. Unowned referentie wordt niet
nilbij vrijgave van het object. Toegang tot een vrijgegeven object via unowned resulteert in een runtime fout.
Cycli van sterke referenties (Retain Cycles): Ontstaan wanneer twee of meer objecten sterke referenties naar elkaar hebben, waardoor geen van beiden wordt vrijgegeven. Oplossingen zijn weak of unowned referenties.
Voorbeeld van een sterke referentiecircuit en de oplossing:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) wordt geïnitialiseerd")
}
deinit {
print("\(name) wordt gedeinitialiseerd")
}
}
class Apartment {
let unit: String
var tenant: Person? // Sterke referentie leidt tot retain cycle
init(unit: String) {
self.unit = unit
print("Appartement \(unit) wordt geïnitialiseerd")
}
deinit {
print("Appartement \(unit) wordt gedeinitialiseerd")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john // Hier ontstaat een retain cycle
john = nil
unit4A = nil
// De initialisatiemethoden worden niet aangeroepen vanwege de retain cycle
Oplossing met weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) wordt geïnitialiseerd")
}
deinit {
print("\(name) wordt gedeinitialiseerd")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Gebruik weak referentie om retain cycle te voorkomen
init(unit: String) {
self.unit = unit
print("Appartement \(unit) wordt geïnitialiseerd")
}
deinit {
print("Appartement \(unit) wordt gedeinitialiseerd")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil
// Beide objecten worden correct gedeinitialiseerd
Unowned vs Weak:
- Gebruik
weakwanneer de referentienilkan worden (object kan als eerste worden vrijgegeven). - Gebruik
unownedwanneer de referentie altijd een waarde zal hebben (het object waarnaar wordt verwezen heeft dezelfde of een langere levensduur).
Closures en cycli van referenties:
Closures kunnen referenties naar objecten vastleggen, wat cycli van sterke referenties creëert. Dit wordt opgelost met een capture list.
Voorbeeld:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[weak self] in // Capture self weakly
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) wordt gedeinitialiseerd")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil
// Object wordt gedeinitialiseerd
Memory debugging:
- Memory Graph Debugger: In Xcode visualiseert de verbindingen tussen objecten en identificeert cycli van sterke referenties.
- Instruments (Allocations, Leaks): Hulpmiddelen voor het monitoren van geheugenallocatie en -vrijgave, en het opsporen van lekken.