Swift-də Avtomatik Yaddaş İdarəetməsi (ARC) necə işləyir?
sobes.tech Süni İntellekt
AI-dan cavab
Swift-də Avtomatik Referans Sayma (ARC) tətbiqlərinizin yaddaş istifadəsini izləyir və idarə edir. O, artıq lazım olmayan zaman sinif nümunələri tərəfindən istifadə olunan yaddaşı avtomatik azad edir və yaddaş sızıntılarının qarşısını alır.
Yeni sinif nümunəsi yaradıldıqda, ARC bu nümunə haqqında məlumat saxlamaq üçün yaddaş blokunu ayırır. Nümunə artıq lazım olmadıqda, ARC həmin yaddaşı azad edir ki, o digər məqsədlər üçün istifadə oluna bilsin.
ARC hər bir sinif nümunəsinə güclü istinadların (strong references) sayını sayır. Güclü istinad, nümunəni yaddaşda saxlayan istinaddır. Güclü istinadların sayı sıfıra çatanda, ARC onunla əlaqəli yaddaşı azad edir.
Swift-də ARC-ə təsir edən üç növ istinad mövcuddur:
- Güclü istinadlar (Strong References): Nümunənin istinad sayını artırır.
- Zəif istinadlar (Weak References): İstinad sayını artırmır. İki sinif nümunəsi bir-birinə güclü istinadlar ilə bağlı olduqda, güclü dövrləri qarşısını almaq üçün istifadə olunur. Zəif istinadlar avtomatik olaraq
nilolur nümunə deinitializasiyası zamanı. - Müəyyən olmayan istinadlar (Unowned References): Həmçinin, istinad sayını artırmır. Əgər bir nümunənin hər zaman mövcud olacağına əminsinizsə, digər nümunə mövcud olduqda. Onlar opsional deyil (
nil). Deinitializasiyadan sonra bu istinadlara giriş cəhdləri icra zamanı xəta ilə nəticələnər.
Güclü dövr nümunəsi nümunəsi:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) başlanır")
}
deinit {
print("\(name) bitir")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
print("Mənzil \(unit) başlanır")
}
deinit {
print("Mənzil \(unit) bitir")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil // Person deinitializasiyalanmır
unit4A = nil // Apartment deinitializasiyalanmır
Məsələnin həlli üçün zəif və ya qeyri-müəyyən istinadlardan istifadə edin. Bu halda, tenant Apartment-də zəif istinad olmalıdır:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) başlanır")
}
deinit {
print("\(name) bitir")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Zəif istinad
init(unit: String) {
self.unit = unit
print("Mənzil \(unit) başlanır")
}
deinit {
print("Mənzil \(unit) bitir")
}
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john?.apartment = unit4A
unit4A?.tenant = john
john = nil // Person deinitializasiyalanır
unit4A = nil // Apartment deinitializasiyalanır
İstinadlar arasında seçim, obyektlər arasındakı münasibətdən asılıdır:
- Zəif: Əgər obyektlərdən biri
nilola bilərsə, digərinin deinitializasiyasından əvvəl (opsional dəyər). - Müəyyən olmayan: Əgər bir obyekt həmişə digər obyekt mövcud olduqda mövcuddursa (opsional olmayan dəyər).
ARC həmçinin sinif nümunələrini tutan bağlamaları (closures) istifadə edən yaddaşı idarə edir. Güclü dövrlər, bağlama bir sinif nümunəsini tutduqda və həmin nümunə də güclü istinadla bağlamaya malik olduqda yaranır. Bu problemi qarşısını almaq üçün, capture listlər istifadə olunur.
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
// Capture list yoxdur, güclü dövr ola bilər
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) deinitializasiya olunur")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "salam, dünya")
print(paragraph!.asHTML())
paragraph = nil // HTMLElement deinitializasiya olunmur
[weak self] istifadə edilən həll:
class AnHTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { [weak self] in // weak self istifadə
guard let self = self else { return "" } // self-in mövcudluğunu yoxlamaq
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) deinitializasiya olunur")
}
}
var paragraph: AnHTMLElement? = AnHTMLElement(name: "p", text: "salam, dünya")
print(paragraph!.asHTML())
paragraph = nil // AnHTMLElement deinitializasiya olunur
[unowned self] istifadə etmək mümkündür, əgər siz əminsinizsə ki, nümunə (self) deinitializasiya olunmazdan əvvəl nil olmayacaq.
ARC, Swift-də yaddaş idarəsini əhəmiyyətli dərəcədə sadələşdirir, lakin referans tiplərini başa düşmək və yaddaş sızıntılarını qarşısını almaq üçün vacibdir.