Sobes.tech
Middle

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:

  1. Güclü istinadlar (Strong References): Nümunənin istinad sayını artırır.
  2. 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 nil olur nümunə deinitializasiyası zamanı.
  3. 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 nil ola 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.