Sobes.tech
Middle

Kuidas töötab automaatse mälu haldamise (ARC) mehhanism Swiftis?

sobes.tech AI

Vastus AI-lt

ARC (Automaatne viidete arvutamine) jälgib ja haldab automaatselt klasside näidete viiteid. See vabastab mälu, mida näide kasutab, kui sellele ei ole enam tugevaid viiteid. ARC töötab ainult klasside näidete puhul, mitte struktuuride või loendite puhul, kuna need on väärtustüübid.

Kolm tüüpi seoseid näidete vahel:

  • Strong (Tugev): Seos, mis suurendab viidete loendurit näidetes. Vaikimisi on kõik viited tugevad.
  • Weak (Nõrk): Seos, mis ei suurenda viidete loendurit. Kasutatakse tugevate tsüklite vältimiseks. weak tüüpi viited on alati valikulised, kuna näide võib vabastada igal ajal.
  • Unowned (Omamata seos): Seos, mis ei suurenda viidete loendurit ja kasutatakse, kui on garanteeritud, et seotud näide eksisteerib kauem kui praegune. Ei ole kohustuslik, kuid proovimisel, kui pääseb ligi vabastatud näitele, tekib jooksu viga.

Tugevad tsüklid tekivad, kui kaks või enam näidet omavad üksteisele tugevaid viiteid, takistades nende vabastamist ARC-i abil. Nende tsüklite lahendamiseks kasutatakse weak või unowned viiteid.

Näide tugeva tsükli kohta:

class Person {
    let name: String
    var apartment: Apartment?

    init(name: String) {
        self.name = name

    }

    deinit { // vabastamise ajal
        print("\(name) vabastatakse")
    }
}

class Apartment {
    let unit: String
    var tenant: Person?

    init(unit: String) {
        self.unit = unit
    }

    deinit { // vabastamise ajal
        print("Korter \(unit) vabastatakse")
    }
}

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 // Mitte midagi ei kuvata, kuna tekkinud tsükkel

Tugeva tsükli lahendamine weak kasutades:

class Person {
    let name: String
    var apartment: Apartment?

    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) vabastatakse")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Nõrk viide Person-ile

    init(unit: String) {
        self.unit = unit
    }

    deinit {
        print("Korter \(unit) vabastatakse")
    }
}

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil // vabastab Person-i
unit4A = nil // vabastab Apartment-i

Tugeva tsükli lahendamine unowned kasutades:

class Customer {
    let name: String
    var card: CreditCard?

    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) vabastatakse")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Omamata viide Customer-ile

    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }

    deinit {
        print("Kaart #\(number) vabastatakse")
    }
}

var john: Customer?

john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

john = nil // vabastab Customer ja CreditCard

ARC ja suletud funktsioonides: Suletud funktsioonid võivad samuti tekitada tsükleid, haarates klasside näiteid. Selle vältimiseks kasutatakse haaramisliste ([weak self] või [unowned self]):

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { // lazy, et saaks kasutada self enne initsialiseerimist
        [unowned self] in // haaramisloend
        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) vabastatakse")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "tere, maailm")
print(paragraph!.asHTML())

paragraph = nil // Vabastab HTMLElement