Ako funguje mechanizmus automatického riadenia pamäti (ARC) v jazyku Swift?
sobes.tech AI
Odpoveď od AI
ARC (Automatické sledovanie odkazov) automaticky sleduje a spravuje odkazy na inštancie tried. Uvoľňuje pamäť obsadenú inštanciou, keď na ňu už nie sú žiadne silné odkazy. ARC funguje iba s inštanciami tried, nie so štruktúrami alebo enumami, pretože sú to typy hodnôt.
Tri typy väzieb medzi inštanciami:
- Silná (Strong): Väzba, ktorá zvyšuje počítadlo odkazov na inštanciu. Predvolene sú všetky odkazy silné.
- Slabá (Weak): Väzba, ktorá nezvyšuje počítadlo odkazov. Používa sa na prevenciu cyklov silných odkazov. Odkazy typu
weaksú vždy voliteľné, pretože inštancia môže byť uvoľnená kedykoľvek. - Nezávislá (Unowned): Väzba, ktorá nezvyšuje počítadlo odkazov a používa sa, keď je zaručené, že súvisiaca inštancia bude existovať dlhšie ako aktuálna. Nie je povinná, ale pri pokuse o prístup k uvoľnenej inštancii spôsobí chybu behu.
Cyklus silných odkazov vzniká, keď dve alebo viac inštancií tried majú navzájom silné odkazy, čím bránia ich uvoľneniu ARC. Na riešenie cyklov sa používajú weak alebo unowned odkazy.
Príklad cyklu silných odkazov:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit { // volá sa pri uvoľnení
print("\(name) sa uvoľňuje")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
}
deinit { // volá sa pri uvoľnení
print("Apartmán \(unit) sa uvoľňuje")
}
}
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 // Nič sa nezobrazí, pretože vznikol cyklus silných odkazov
Riešenie cyklu silných odkazov pomocou weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit {
print("\(name) sa uvoľňuje")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Slabý odkaz na Person
init(unit: String) {
self.unit = unit
}
deinit {
print("Apartmán \(unit) sa uvoľňuje")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Uvoľní Person
unit4A = nil // Uvoľní Apartment
Riešenie cyklu silných odkazov pomocou unowned:
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) sa uvoľňuje")
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer // Bývalý odkaz na Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Karta #\(number) sa uvoľňuje")
}
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil // Uvoľní Customer a CreditCard
ARC v uzávierkach: Uzávierky môžu tiež vytvárať cykly odkazov, zachytávajúc inštancie tried. Na prevenciu sa používajú zoznamy zachytávania ([weak self] alebo [unowned self]).
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { // lazy na možnosť použiť self pred inicializáciou
[unowned self] in // zoznam zachytávania s "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) sa uvoľňuje")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "ahoj, svet")
print(paragraph!.asHTML())
paragraph = nil // Uvoľní HTMLElement