Sobes.tech
Middle

Ինչպես է աշխատում ավտոմատ հիշողության կառավարումը (ARC) Swift լեզվում?

sobes.tech AI

Պատասխան AI-ից

ARC (Ավտոմատ ռեֆերանսի հաշվարկ) ավտոմատ կերպով հետևում և կառավարում է դասի օրինակների հղումները: Այն ազատում է հիշողությունը, որը զբաղեցված է օրինակով, երբ նրա վրա այլ ուժեղ հղումներ չկան: ARC աշխատում է միայն դասի օրինակների հետ, ոչ թե կառուցվածքների կամ ցուցակների, քանի որ դրանք արժեքային տիպեր են:

Երեք տեսակի կապեր օրինակների միջև՝

  • Strong (ուժեղ): Կապ, որը մեծացնում է հղումների հաշվիչը օրինակին: Դեպքում բոլոր հղումները ուժեղ են:
  • Weak (թույլ): Կապ, որը չի մեծացնում հղումների հաշվիչը: Օգտագործվում է ուժեղ հղումների ցիկլերը կանխելու համար: weak տեսակի հղումները միշտ ընտրովի են, քանի որ օրինակն կարող է ազատվել ցանկացած պահի:
  • Unowned (անհատական): Կապ, որը չի մեծացնում հղումների հաշվիչը և օգտագործվում է, երբ երաշխավորված է, որ կապված օրինակն ավելի երկար կկայացվի, քան ընթացիկը: Անհրաժեշտ չէ, բայց փորձելիս, եթե հասանելի է ազատված օրինակին, առաջացնում է գործնական սխալ:

Ցիկլեր ուժեղ հղումների առաջանում են, երբ երկու կամ ավելի օրինակներ ունեն ուժեղ հղումներ միմյանց, կանխելով նրանց ազատումը ARC-ով: Ցիկլերը լուծելու համար օգտագործվում են weak կամ unowned հղումներ:

Օրինակ ուժեղ հղումների ցիկլի:

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

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

    deinit { // ազատման ժամանակ
        print("\(name) ազատվում է")
    }
}

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

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

    deinit { // ազատման ժամանակ
        print("Բնակարան \(unit) ազատվում է")
    }
}

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 // Ոչինչ չի տպվում, քանի որ առաջացել է ցիկլ ուժեղ հղումների

Ցիկլեր ուժեղ հղումների լուծում weak օգտագործելով:

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

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

    deinit {
        print("\(name) ազատվում է")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Թույլ հղում Person-ին

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

    deinit {
        print("Բնակարան \(unit) ազատվում է")
    }
}

var john: Person?
var unit4A: Apartment?

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

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

john = nil // Ազատում է Person-ին
unit4A = nil // Ազատում է Apartment-ին

Ցիկլեր ուժեղ հղումների լուծում unowned օգտագործելով:

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

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

    deinit {
        print("\(name) ազատվում է")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Անհատական հղում Customer-ին

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

    deinit {
        print("Քարտ #\(number) ազատվում է")
    }
}

var john: Customer?

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

john = nil // Ազատում է Customer և CreditCard

ARC-ը փակման մեջ. Փակումները կարող են նաև ստեղծել ցիկլեր, բռնելով դասի օրինակները: Դրա կանխարգելման համար օգտագործվում են բռնագրավման ցանկեր ([weak self] կամ [unowned self]):

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

    lazy var asHTML: () -> String = { // lazy՝ հնարավոր է օգտագործել self-ը նախքան ինիցիալիզացիան
        [unowned self] in // բռնագրավման ցանկ՝ "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) ազատվում է")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "հարց, աշխարհ")
print(paragraph!.asHTML())

paragraph = nil // Ազատում է HTMLElement