Jak funguje mechanismus automatického řízení paměti (ARC) v jazyce Swift?
sobes.tech AI
Odpověď od AI
ARC (Automatické počítání odkazů) automaticky sleduje a spravuje odkazy na instance tříd. Uvolňuje paměť obsazenou instancí, když na ni již nejsou žádné silné odkazy. ARC funguje pouze s instancemi tříd, nikoli se strukturami nebo výčty, protože ty jsou hodnotové typy.
Tři typy odkazů mezi instancemi:
- Strong (Silný): Odkaz, který zvyšuje čítač odkazů na instanci. Výchozí jsou všechny odkazy silné.
- Weak (Slabý): Odkaz, který nezvyšuje čítač odkazů. Používá se k prevenci cyklů silných odkazů. Odkazy
weakjsou vždy volitelné, protože instance může být uvolněna kdykoli. - Unowned (Nezávislý): Odkaz, který nezvyšuje čítač odkazů a používá se, když je zaručeno, že přidružená instance bude existovat déle než aktuální. Není povinný, ale pokus o přístup k uvolněné instanci způsobí běhovou chybu.
Cyklus silných odkazů vzniká, když dvě nebo více instancí třídy má navzájem silné odkazy, což brání jejich uvolnění ARC. Pro řešení těchto cyklů se používají odkazy weak nebo unowned.
Příklad cyklu silných odkazů:
class Person {
let jméno: String
var byt: Apartment?
init(jméno: String) {
self.jméno = jméno
}
deinit { // volá se při uvolnění
print("\(jméno) je uvolněn")
}
}
class Apartment {
let jednotka: String
var nájemník: Person?
init(jednotka: String) {
self.jednotka = jednotka
}
deinit { // volá se při uvolnění
print("Byt \(jednotka) je uvolněn")
}
}
var john: Person?
var jednotka4A: Apartment?
john = Person(jméno: "John Appleseed")
jednotka4A = Apartment(jednotka: "4A")
john!.byt = jednotka4A
jednotka4A!.nájemník = john
john = nil
jednotka4A = nil // Nic se nezobrazí, protože je cyklus silných odkazů
Řešení cyklu silných odkazů pomocí weak:
class Person {
let jméno: String
var byt: Apartment?
init(jméno: String) {
self.jméno = jméno
}
deinit {
print("\(jméno) je uvolněn")
}
}
class Apartment {
let jednotka: String
weak var nájemník: Person? // Slabý odkaz na Person
init(jednotka: String) {
self.jednotka = jednotka
}
deinit {
print("Byt \(jednotka) je uvolněn")
}
}
var john: Person?
var jednotka4A: Apartment?
john = Person(jméno: "John Appleseed")
jednotka4A = Apartment(jednotka: "4A")
john!.byt = jednotka4A
jednotka4A!.nájemník = john
john = nil // Uvolní Person
jednotka4A = nil // Uvolní Apartment
Řešení cyklu silných odkazů pomocí unowned:
class Customer {
let jméno: String
var karta: CreditCard?
init(jméno: String) {
self.jméno = jméno
}
deinit {
print("\(jméno) je uvolněn")
}
}
class CreditCard {
let číslo: UInt64
unowned let zákazník: Customer // Nevlastní odkaz na Customer
init(číslo: UInt64, zákazník: Customer) {
self.číslo = číslo
self.zákazník = zákazník
}
deinit {
print("Karta #\(číslo) je uvolněna")
}
}
var john: Customer?
john = Customer(jméno: "John Appleseed")
john!.karta = CreditCard(číslo: 1234_5678_9012_3456, zákazník: john!)
john = nil // Uvolní Customer a CreditCard
ARC v uzávěrech: Uzávěry mohou také vytvářet cykly silných odkazů tím, že zachycují instance tříd. K tomu se používají seznamy zachycení ([weak self] nebo [unowned self]).
class HTMLElement {
let jméno: String
let text: String?
lazy var jakoHTML: () -> String = { // lazy pro možnost použití self před inicializací
[unowned self] in // Seznam zachycení s "unowned self"
if let text = self.text {
return "<\(self.jméno)>\(text)</\(self.jméno)>"
} else {
return "<\(self.jméno) />"
}
}
init(jméno: String, text: String? = nil) {
self.jméno = jméno
self.text = text
}
deinit {
print("\(jméno) je uvolněn")
}
}
var odstavec: HTMLElement? = HTMLElement(jméno: "p", text: "hello, world")
print(odstavec!.jakoHTML())
odstavec = nil // Uvolní HTMLElement