Kaip veikia automatinės atminties valdymo (ARC) mechanizmas Swift kalboje?
sobes.tech AI
Atsakymas iš AI
ARC (Automatinis nuorodžių skaičiavimas) automatiškai stebi ir valdo nuorodas į klasių pavyzdžius. Jis atlaisvina atmintį, užimamą pavyzdžio, kai nėra jokių stiprių nuorodų į jį. ARC veikia tik su klasių pavyzdžiais, o ne su struktūromis ar išvardijimais, nes jie yra reikšmių tipai.
Tarp pavyzdžių yra trys ryšių tipai:
- Strong (Stiprus): Ryšys, kuris padidina nuorodų skaitiklį pavyzdyje. Pagal numatytuosius nustatymus visi ryšiai yra stiprūs.
- Weak (Silpnas): Ryšys, kuris nepadidina nuorodų skaitiklio. Naudojamas stiprių nuorodų ciklų prevencijai.
weaktipo nuorodos visada yra pasirinktinės, nes pavyzdys gali būti atlaisvintas bet kuriuo metu. - Unowned (Nepavaldus): Ryšys, kuris nepadidina nuorodų skaitiklio ir naudojamas, kai garantuojama, kad susijęs pavyzdys egzistuos ilgiau nei dabartinis. Nebūtina, bet bandant pasiekti atlaisvintą pavyzdį, kyla vykdymo klaida.
Stiprių nuorodų ciklai atsiranda, kai du ar daugiau klasių pavyzdžių turi stiprius ryšius vienas su kitu, užkertant kelią jų atlaisvinimui ARC. Šių ciklų sprendimui naudojami weak arba unowned ryšiai.
Pavyzdys stiprių nuorodų ciklo:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit { // išlaisvinimo metu
print("\(name) yra išlaisvinamas")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
}
deinit { // išlaisvinimo metu
print("Butas \(unit) yra išlaisvinamas")
}
}
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 // Nieko neatsitinka, nes susidarė ciklas
Sprendimas stiprių nuorodų ciklui naudojant weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit {
print("\(name) yra išlaisvinamas")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Silpna nuoroda į Person
init(unit: String) {
self.unit = unit
}
deinit {
print("Butas \(unit) yra išlaisvinamas")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Išlaisvina Person
unit4A = nil // Išlaisvina Apartment
Sprendimas stiprių nuorodų ciklui naudojant unowned:
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) yra išlaisvinamas")
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer // Nepavaldus ryšys
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Kortelė #\(number) yra išlaisvinama")
}
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil // Išlaisvina Customer ir CreditCard
ARC ir uždarymuose: Uždarymai taip pat gali sukelti ciklus, įtvirtindami klasių pavyzdžius. Norint to išvengti, naudojami [weak self] arba [unowned self] įrašai:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { // lazy, kad galėtų naudoti self prieš inicializaciją
[unowned self] in // įtvirtinimo sąrašas
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) yra išlaisvinamas")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "labas, pasaulis")
print(paragraph!.asHTML())
paragraph = nil // Išlaisvina HTMLElement