Sobes.tech
Middle

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 weak sú 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