ԻՕՍ-ում պահպանումների շրջաններ (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-ին փակման մեջ, կանխելով պահպանումների շղթան: