Sobes.tech
Middle

Kā darbojas automātiskās atmiņas pārvaldības (ARC) mehānisms Swift valodā?

sobes.tech AI

Atbilde no AI

ARC (Automātiskā atsauču skaitīšana) automātiski uzrauga un pārvalda atsauces uz klases piemēriem. Tas atbrīvo atmiņu, ko aizņem piemērs, kad uz to vairs nav stipru atsauču. ARC darbojas tikai ar klases piemēriem, nevis ar struktūrām vai enumerācijām, jo tie ir vērtību tipi.

Trīs veidu saites starp piemēriem:

  • Strong (Spēcīga): Saite, kas palielina atsauču skaitītāju piemēram. Noklusējuma visām saitēm ir stipras.
  • Weak (Vāja): Saite, kas nesasniedz atsauču skaitītāju. Izmanto, lai novērstu stipro saišu ciklus. weak tipa saites vienmēr ir opcijas, jo piemērs var tikt atbrīvots jebkurā brīdī.
  • Unowned (Nepiederīgs): Saite, kas nesasniedz atsauču skaitītāju un tiek izmantota, kad garantēts, ka saistītais piemērs pastāvēs ilgāk nekā pašreizējais. Nav obligāta, bet, mēģinot piekļūt atbrīvotam piemēram, rodas izpildes kļūda.

Stipro saišu cikli rodas, kad divi vai vairāk piemēru ir stipras saites viens uz otru, novēršot to atbrīvošanu ARC. Šos ciklus risina, izmantojot weak vai unowned saites.

Stipru saišu cikla piemērs:

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

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

    deinit { // izbeigšanas laikā
        print("\(name) tiek atbrīvots")
    }
}

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

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

    deinit { // izbeigšanas laikā
        print("Dzīvoklis \(unit) tiek atbrīvots")
    }
}

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 // Nekas netiek izvadīts, jo ir cikls

Risinājums stipru saišu ciklam ar weak:

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

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

    deinit {
        print("\(name) tiek atbrīvots")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Vāja saite uz Person

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

    deinit {
        print("Dzīvoklis \(unit) tiek atbrīvots")
    }
}

var john: Person?
var unit4A: Apartment?

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

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

john = nil // Atbrīvo Person
unit4A = nil // Atbrīvo Apartment

Risinājums stipru saišu ciklam ar unowned:

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

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

    deinit {
        print("\(name) tiek atbrīvots")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Nepiederīgs saite uz Customer

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

    deinit {
        print("Karte #\(number) tiek atbrīvota")
    }
}

var john: Customer?

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

john = nil // Atbrīvo Customer un CreditCard

ARC un slēdzenes: Slēdzenes arī var radīt ciklus, aizskarot klases piemērus. Lai to novērstu, tiek izmantoti [weak self] vai [unowned self]:

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

    lazy var asHTML: () -> String = { // lazy, lai izmantotu self pirms inicializācijas
        [unowned self] in // aizskaršanas saraksts
        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) tiek atbrīvots")
    }
}

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

paragraph = nil // Atbrīvo HTMLElement