Hogyan működik az automatik memória kezelés (ARC) mechanizmusa a Swift nyelvben?
sobes.tech MI
Válasz az MI-től
Az ARC (Automatikus Referenciaszámolás) automatikusan követi és kezeli a példányokra mutató hivatkozásokat. Felszabadítja a memóriát, amelyet egy példány foglal el, amikor már nincs rá erős hivatkozás. Az ARC csak osztálypéldányokkal működik, nem struktúrákkal vagy felsorolásokkal, mivel ezek értéktípusok.
Három típusú hivatkozás az példányok között:
- Strong (Erős): Egy hivatkozás, amely növeli az példány hivatkozásszámát. Alapértelmezés szerint minden hivatkozás erős.
- Weak (Gyenge): Egy hivatkozás, amely nem növeli a hivatkozásszámot. Használják az erős ciklusok elkerülésére. A
weaktípusú hivatkozások mindig opcionálisak, mivel az példány bármikor felszabadulhat. - Unowned (Független): Egy hivatkozás, amely nem növeli a hivatkozásszámot, és akkor használják, amikor garantált, hogy a kapcsolódó példány hosszabb ideig fog létezni, mint a jelenlegi. Nem kötelező, de a felszabadított példányhoz való hozzáférés futásidejű hibát okoz.
Az erős ciklusok akkor fordulnak elő, amikor két vagy több osztálypéldány erős hivatkozásokat tart egymásra, megakadályozva azok felszabadulását az ARC által. Ezek megoldására weak vagy unowned hivatkozásokat használnak.
Példa erős ciklusra:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit { // felszabaduláskor hívódik
print("\(name) felszabadul")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
}
deinit { // felszabaduláskor hívódik
print("Lakás \(unit) felszabadul")
}
}
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 // Semmi nem jelenik meg, mert erős ciklus van
Az erős ciklusok megoldása weak használatával:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
}
deinit {
print("\(name) felszabadul")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Gyenge hivatkozás
init(unit: String) {
self.unit = unit
}
deinit {
print("Lakás \(unit) felszabadul")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Felszabadítja a Person-t
unit4A = nil // Felszabadítja a Lakást
Az erős ciklusok megoldása unowned használatával:
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) felszabadul")
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer // Független hivatkozás
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Kártya #\(number) felszabadul")
}
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil // Felszabadítja a Customer-t és a CreditCard-t
ARC closure-ökben: A closure-k is képesek erős ciklusokat létrehozni, mivel példányokat foghatnak el. Ezt megelőzendő, a [weak self] vagy [unowned self] használatos.
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { // lazy, hogy self-t használhasson az inicializálás előtt
[unowned self] in // Elfogási lista "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) felszabadul")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "helló, világ")
print(paragraph!.asHTML())
paragraph = nil // HTMLElement felszabadul