Kako funkcioniše mehanizam automatskog upravljanja memorijom (ARC) u jeziku Swift?
sobes.tech АИ
Одговор од АИ
ARC (Automatsko brojanje referenci) automatski prati i upravlja referencama na instance klasa. On oslobađa memoriju koju zauzima instanca kada na nju više nema jakih referenci. ARC radi samo sa instancama klasa, a ne sa strukturama ili enumeracijama, jer su one tipovi-vrednosti.
Tri tipa referenci između instanci:
- Strong (Jaka): Referenca koja povećava brojač referenci na instanci. Podrazumevano, sve reference su jake.
- Weak (Slaba): Referenca koja ne povećava brojač referenci. Koristi se za sprečavanje cikličnih jaza jakih referenci.
weakreference su uvek opcionalne, jer instanca može biti oslobođena u bilo kom trenutku. - Unowned (Neposedovana): Referenca koja ne povećava brojač referenci i koristi se kada je garantovano da će povezani primerak postojati duže od trenutnog. Nije obavezno, ali pokušaj pristupa oslobođenom primerku izazvaće grešku u izvršenju.
Ciklični jaci odnosi nastaju kada dve ili više instanci klase imaju jake reference jedna na drugu, sprečavajući njihovo oslobađanje od strane ARC. Za rešavanje cikličnih odnosa koriste se weak ili unowned reference.
Primer cikličnog jaza:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit { // poziva se pri oslobađanju
print("\(name) se oslobađa")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
}
deinit { // poziva se pri oslobađanju
print("Stan \(unit) se oslobađa")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Ništa se ne ispisuje, jer postoji ciklični jaci odnosi
unit4A = nil // Ništa se ne ispisuje, jer postoji ciklični jaci odnosi
Rešenje cikličnog jaza korišćenjem weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit {
print("\(name) se oslobađa")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Slaba referenca na Person
init(unit: String) {
self.unit = unit
}
deinit {
print("Stan \(unit) se oslobađa")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Oslobađa Person
unit4A = nil // Oslobađa Apartment
Rešenje cikličnog jaza korišćenjem unowned:
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) se oslobađa")
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer // Bezposedna referenca na Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Karta #\(number) se oslobađa")
}
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil // Oslobađa Customer i CreditCard
ARC u zatvaranjima: Zatvaranja takođe mogu stvoriti ciklične odnose, "hvatajući" instance klasa. Za sprečavanje toga koriste se liste hvatanja ([weak self] ili [unowned self]).
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { // lazy za mogućnost korišćenja self pre inicijalizacije
[unowned self] in // Lista hvatanja sa "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) se oslobađa")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "zdravo, svet")
print(paragraph!.asHTML())
paragraph = nil // HTMLElement se oslobađa