Sobes.tech
Middle

Swiftте автоматтык эс тутумду башкаруу (ARC) кантип иштейт?

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("Квартира \(unit) ишке киргизилди")
    }

    deinit {
        print("Квартира \(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? // Weak reference колдонуу

    init(unit: String) {
        self.unit = unit
        print("Квартира \(unit) ишке киргизилди")
    }

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

Тандоо слаб же бош шилтемелердин ортосунда, объекттердин ортосундагы мамилеге байланыштуу:

  • Weak: Эгер бир объект башка объектке nil болушу мүмкүн болсо, ал опционалдуу мааниде болот.
  • Unowned: Эгер бир объект дайыма башка объекттин ичинде болот жана ал өзгөрбөсө, анда ал опционал эмес болот.

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) жабык циклдин ичинде nil болбойт:

ARC Swiftте эс тутумду башкарууну автоматташтырып, оңой кылды, бирок шилтемелердин түрлөрүн түшүнүү керек, анткени ал эс тутумдун агып кетишин алдын алат.