Hoe werkt het mechanisme voor automatische geheugenbeheer (ARC) in de Swift-taal?
sobes.tech AI
Antwoord van AI
ARC (Automatische Referentie Telling) volgt automatisch en beheert de referenties naar klasse-instanties. Het vrijmaakt geheugen dat door een instantie wordt ingenomen wanneer er geen sterke referenties meer naar zijn. ARC werkt alleen met klasse-instanties, niet met structuren of enumeraties, omdat deze waarde-typen zijn.
Drie soorten referenties tussen instanties:
- Strong (Sterk): Een referentie die de referentieteller van een instantie verhoogt. Standaard zijn alle referenties sterk.
- Weak (Zwak): Een referentie die de teller niet verhoogt. Gebruikt om cycli van sterke referenties te voorkomen.
weak-referenties zijn altijd optioneel, omdat de instantie op elk moment kan worden vrijgemaakt. - Unowned (Ongeowned): Een referentie die de teller niet verhoogt en wordt gebruikt wanneer gegarandeerd is dat de gekoppelde instantie langer zal bestaan dan de huidige. Niet verplicht, maar het proberen te benaderen van een vrijgemaakte instantie veroorzaakt een runtime-fout.
Sterke referentiecycli ontstaan wanneer twee of meer klasse-instanties sterke referenties naar elkaar hebben, waardoor hun vrijgave door ARC wordt voorkomen. Om cycli op te lossen, worden weak of unowned referenties gebruikt.
Voorbeeld van een sterke referentiecyclus:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit { // wordt aangeroepen bij vrijgave
print("\(name) wordt gedeinitialiseerd")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
}
deinit { // wordt aangeroepen bij vrijgave
print("Appartement \(unit) wordt gedeinitialiseerd")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil // Niets wordt afgedrukt, omdat er een cyclus van sterke referenties is
Oplossen van een sterke referentiecyclus met weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit {
print("\(name) wordt gedeinitialiseerd")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Zwakke referentie naar Person
init(unit: String) {
self.unit = unit
}
deinit {
print("Appartement \(unit) wordt gedeinitialiseerd")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Verwijdert Person
unit4A = nil // Verwijdert Apartment
Oplossen van een sterke referentiecyclus met unowned:
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) wordt gedeinitialiseerd")
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer // Ongeowned referentie naar Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Kaart #\(number) wordt gedeinitialiseerd")
}
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil // Verwijdert Customer en CreditCard
ARC in closures: Closures kunnen ook sterke cycli van referenties creëren door instanties van klassen te vangen. Om dit te voorkomen, worden capture-lijsten gebruikt ([weak self] of [unowned self]).
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { // lazy om self te kunnen gebruiken vóór initialisatie
[unowned self] in // Capture-lijst met "unowned self"
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
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 // Verwijdert HTMLElement