Sobes.tech
Middle

Чӣ гуна кор мекунад идораи худкории хотира (ARC) дар Swift?

sobes.tech AI

Ҷавоб аз AI

ARC (Автоматиии ҳисоб кардани истинодҳо) дар Swift пайгирӣ ва идоракунии истифодаи хотираи барномаҳои шумост. Он ба таври автоматӣ блокҳои хотираро, ки аз ҷониби намунаҳои синфҳо истифода мешаванд, озод мекунад, вақте ки онҳо дигар лозим нестанд, ки ин ба пешгирии фиребҳои хотира кӯмак мекунад.

Ҳангоми эҷоди намунаи нав аз синф, ARC блоки хотираро барои нигоҳ доштани маълумот дар бораи он намуна тақсим мекунад. Вақте ки намуна дигар лозим нест, ARC ин хотираро озод мекунад, то барои дигар мақсадҳо истифода шавад.

ARC бо ҳисоб кардани шумораи истинодҳои қавӣ (strong references) ба ҳар як намунаи синф кор мекунад. Истиноди қавӣ истинодест, ки намунаи синфро дар хотира нигоҳ медорад. Вақте ки шумораи истинодҳои қавӣ ба намуна ба сифр мерасад, ARC хотираро озод мекунад.

Дар Swift се намуди истинодҳо мавҷуданд, ки ба ARC таъсир мерасонанд:

  1. Истинодҳои қавӣ (Strong References): шумораи истинодҳоро ба намуна зиёд мекунанд.
  2. Истинодҳои суст (Weak References): шумораи истинодҳоро зиёд намекунанд. Онҳоро барои пешгирии циклҳои истинодҳои қавӣ истифода мебаранд, вақте ки ду намунаи синф истинодҳои қавиро ба ҳам нигоҳ медоранд. Истиноди суст автоматӣ ба nil табдил меёбад вақте ки объекте, ки ба он ишора мекунад, деинициализатсия мешавад.
  3. Истинодҳои беқарор (Unowned References): инчунин шумораи истинодҳоро зиёд намекунанд. Онҳоро вақте истифода мебаранд, ки шумо боварӣ доред, ки объекте, ки ба он ишора мекунад, ҳамеша ҳузур дорад, то вақте ки ҳозира аст. Онҳо опсионалӣ нестанд (nil). кӯшиши дастрасӣ ба объекте, ки деинициализатсия шудааст, бо истиноди беқарор хатогии иҷроиро ба вуҷуд меорад.

Масалан, цикли истинодҳои қавӣ:

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) ҳангоми деинициализатсия")
    }
}

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 деинициализатсия намешавад

Барои ҳалли ин масъала, истифодаи истинодҳои суст ё беқарорро истифода баред. Дар ин ҳолат, tenant дар Apartment бояд истиноди суст бошад:

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

    init(name: String) {
        self.name = name
        print("\(name) ҳангоми оғозёбӣ")
    }

    deinit {
        print("\(name) ҳангоми деинициализатсия")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Истифодаи истиноди суст

    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) ҳангоми оғозёбӣ")
    }

    deinit {
        print("Apartment \(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 деинициализатсия мешавад

Интихоб байни истиноди суст ва беқарор вобаста ба муносибати байни объектҳо:

  • Суст: Агар яке аз объектҳо метавонад nil шавад пеш аз он ки дигаре деинициализатсия шавад (қимати опционалӣ).
  • Беқарор: Агар яке аз объектҳо ҳамеша вуҷуд дошта бошад, то вақте ки дигаре вуҷуд дорад (қимати ғайриопционалӣ).

ARC инчунин хотираро, ки аз ҷониби занҷирҳо (closures) истифода мешавад, идора мекунад, ки намунаҳои синфҳоро дар бар мегирад. Циклҳои истинодҳои қавӣ метавонанд дар вақте ки занҷир намунаи синфро захира мекунад ва он намуна ҳамчунин истиноди қавӣ ба занҷир дорад, ба вуҷуд оянд. Барои пешгирӣ аз ин, рӯйхатҳои захира (capture lists) дар занҷирҳо истифода мешаванд.

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

    lazy var asHTML: () -> String = {
        // Бе рӯйхати захира, мумкин аст цикл қавӣ
        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: "hello, world")
print(paragraph!.asHTML())

paragraph = nil // HTMLElement ҳангоми деинициализатсия намешавад

Ҳалли бо истифода аз рӯйхати захира [weak self]:

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

    lazy var asHTML: () -> String = { [weak self] in // Истифодаи weak self
        guard let self = self else { return "" } // Санҷиши мавҷудияти 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: AnHTMLElement? = AnHTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())

paragraph = nil // AnHTMLElement деинициализатсия мешавад

Истифодаи [unowned self] имконпазир аст, агар шумо боварӣ дошта бошед, ки намунаи синф (self) пеш аз иҷрои занҷир нолӣ намешавад.

ARC ба таври назаррас идоракунии хотираро дар Swift содда мекунад, дар муқоиса бо идоракунии дастӣ, аммо талаб мекунад, ки намудҳои истинодҳоро фаҳмед, то аз фиребҳои хотира пешгирӣ кунед.