Sobes.tech
Middle

Խոսեք մեզ iOS-ի հիշողության կառավարման մասին։

sobes.tech AI

Պատասխան AI-ից

iOS օգտագործում է ավտոմատ հիշողության կառավարում՝ ARC (Automatic Reference Counting) միջոցով: ARC ինքնաբերաբար ազատում է օբյեկտները, երբ նրանց վրա այլ հղումներ չկան:

Հիմնական հասկացությունները՝

  • Strong Reference: Օբյեկտի հղման հաշվիչը բարձրացնում է: Օբյեկտը չի ազատվի, քանի դեռ կա ուժեղ հղում:
  • Weak Reference: Չբարձրացնում է հղման հաշվիչը: Օգտագործվում է ուժեղ հղումների ցիկլերը կանխելու համար: Հղում է դեպի օբյեկտ, որը կարող է ազատվել: Եթե օբյեկտը ազատվի, weak հղումը դառնում է nil:
  • Unowned Reference: Դիպուկ նման է weak-ին, բայց չի դառնում nil օբյեկտի ազատման ժամանակ: Օգտագործվում է, երբ օբյեկտը միշտ առկա է կամ ունի նույն կամ երկարատև կյանք:

Ցիկլեր ուժեղ հղումների (Retain Cycles): առաջանում են, երբ երկու կամ ավելի օբյեկտներ ունեն միմյանց ուժեղ հղումներ, ինչը խոչընդոտում է նրանց ազատմանը:

Օրինակ՝

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 հղում՝ ցիկլը կանխելու համար

    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) սկսում է աշխատել")
    }

    deinit {
        print("Apartment \(unit) ավարտում է")
    }
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john // Այստեղ առաջանում է ցիկլ

john = nil
unit4A = nil
// Դե-ինիցիալիզացիայի մեթոդները չեն կանչվում ցիկլի պատճառով

Որպես լուծում՝ օգտագործել weak:

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 հղում՝ ցիկլը կանխելու համար

    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) սկսում է աշխատել")
    }

    deinit {
        print("Apartment \(unit) ավարտում է")
    }
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A = nil
// Երկու օբյեկտներն էլ ճիշտ կերպով դե-ինիցիալիզացվում են

Unowned vs Weak:

  • Օգտագործիր weak, երբ հղումը կարող է դառնալ nil (օբյեկտը կարող է առաջինը ազատվել)
  • Օգտագործիր unowned, երբ հղումը միշտ կունենա արժեք (օբյեկտը, որի վրա հղում է, ունի նույն կամ երկարատև կյանք)

Closure-ներ և ցիկլեր հղումներ:

Closure-ները կարող են բռնել օբյեկտների հղումներ, ստեղծելով ուժեղ ցիկլեր: Սա լուծվում է capture list-ով:

Օրինակ՝

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

    lazy var asHTML: () -> String = {
        [weak self] in // բռնում ենք `self`-ին թույլ հղումով
        guard let self = self else {
            return ""
        }
        var html = "<\(self.name)"
        if let text = self.text {
            html += ">\(text)</\(self.name)>"
        } else {
            html += " />"
        }
        return html
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) ավարտում է")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "բարև, աշխարհ")
print(paragraph!.asHTML())

paragraph = nil
// Օբյեկտը դե-ինիցիալիզացվում է

Հիշողության խնդիրների դե-բագինգ:

  • Memory Graph Debugger: Xcode- ում թույլ է տալիս տեսնել օբյեկտների կապերը և հայտնաբերել ցիկլեր
  • Instruments (Allocations, Leaks): Օգտագործվում է հիշողության բաշխումը և ազատումը մոնիտորինգի համար, նաև թափանցիկության որոնման համար։