Sobes.tech
Middle

ԻՕՍ-ում պահպանումների շրջաններ (retain cycles) ինչ են?

sobes.tech AI

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

Կրկնվող պահպանումը առաջանում է, երբ երկու կամ ավելի օբյեկտներ ունեն ուժեղ հղումներ միմյանց, ստեղծելով "փակ շղթա": Այսպիսով, յուրաքանչյուր օբյեկտի հղման հաշվիչը երբեք չի հասնի զրոյի, և այն չի կարող ազատվել ARC (Automatic Reference Counting) կողմից: Սա հանգեցնում է հիշողության լքման, քանի որ օբյեկտները մնում են հիշողության մեջ նույնիսկ այն ժամանակ, երբ նրանք այլևս չեն օգտագործվում:

Օրինակ:

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

    init(name: String) {
        self.name = name
        print("\(name) սկսում է աշխատել")
    }

    deinit {
        print("\(name) ավարտում է աշխատել")
    }
}

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

    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) սկսում է աշխատել")
    }

    deinit {
        print("Apartment \(unit) ավարտում է աշխատել")
    }
}

Այս օրինակով, եթե Person ունի ուժեղ հղում Apartment-ին, և Apartment ունի ուժեղ հղում Person-ին, ապա երբ փորձեք ազատել այդ օբյեկտները, նրանք չեն ջնջվի, քանի որ նրանց հղման հաշվիչները չեն հասնի զրոյի:

Ինչպես լուծել պահպանումների շղթաների խնդիրը:

Օգտագործեք թեթև (weak) կամ անհայտ (unowned) հղումներ:

  • weak: Օգտագործվում է, երբ հնարավոր է, որ կապված օբյեկտը nil դառնա կյանքի ցիկլի ընթացքում մյուս օբյեկտի: Հղումը ավտոմատ կերպով դառնում է nil, երբ այն օբյեկտը, որի վրա հղում է, ազատվում է: Սա ընտրովի է:
  • unowned: Օգտագործվում է, երբ հայտնի է, որ կապված օբյեկտը ունի նույն կամ երկարաժամկետ կյանք, քան հղումը ունեցող օբյեկտը: Չի կարող լինել nil:

Նորացված օրինակ weak օգտագործելով:

Փոխում ենք tenant հղումը Apartment դասում՝ որպես թեթև:

class Apartment {
    let unit: String
    weak var tenant: Person? // օգտագործում ենք weak

    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) սկսում է աշխատել")
    }

    deinit {
        print("Apartment \(unit) ավարտում է աշխատել")
    }
}

Այժմ, երբ Person օբյեկտը ազատվում է, tenant հղումը Apartment-ում ավտոմատ կերպով դառնում է nil, խզելով պահպանումների շղթան և թույլ տալով նաև Apartment-ի ազատումը:

weak և unowned համեմատություն:

Գծագիր weak unowned
Հղման տեսակ Ընտրովի Անընտրովի
Կարող է լինել nil? Այո, երբ օբյեկտը ազատվում է Ոչ
Երբ օգտագործել? Երբ օբյեկտը կարող է լինել nil Երբ օբյեկտը չի կարող լինել nil
Գործողություն Փոքր-ինչ դանդաղ, քանի որ անհրաժեշտ է nil ստուգում Փոքր-ինչ արագ, քանի որ nil ստուգում չկա

Բացի այդ, պահպանումների շղթաները կարող են առաջանալ նաև փակման (closures) մեջ:

Երբ փակումը բռնում է ինստանսիայի հատկությունները կամ self, այն կարող է ստեղծել ուժեղ հղում օբյեկտին: Եթե այդ օբյեկտը նաև ունի ուժեղ հղում փակմանը (օրինակ, հատկության կամ դելեգատի միջոցով), ապա առաջանում է պահպանումների շղթա:

Ինչպես լուծել պահպանումների շղթաները փակման մեջ:

Օգտագործեք հավաքածուի ցուցակ (capture list):

class SomeClass {
    var value = 0

    func doSomethingDelayed() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in // capture list՝ weak self
            guard let self = self else { return } // `nil` ստուգում՝ `weak self` համար
            self.value += 1
            print("Արժեքը այժմ \(self.value)")
        }
    }
}

Այս օրինակով, [weak self] ստեղծում է թույլ հղում self-ին փակման մեջ, կանխելով պահպանումների շղթան: