Sobes.tech
Middle

Rääkige meile iOS-i mäluhaldusest.

sobes.tech AI

Vastus AI-lt

iOS kasutab automaatset mäluhaldamist ARC (Automatic Reference Counting) kaudu. ARC vabastab automaatselt objektid, kui neile ei ole enam viiteid:

Peamised kontseptsioonid:

  • Tugev viide: Suurendab objekti viidete loendit. Objekt ei vabastata, kuni sellele on tugevad viited.
  • Nõrk viide: Ei suurenda viidete loendit. Kasutatakse tugevate viidete tsüklite vältimiseks. Viitab objektile, mida võib vabastada. Kui objekt vabastatakse, muutub nõrk viide nil-iks.
  • Mitteomandatud viide: Sarnane nõrgale, kuid ei muutu nil-iks objekti vabastamisel. Kasutatakse, kui objektil on sama või pikem elutsükkel. Mitteomandatud viide ei muutu nil-iks objekti vabastamisel. Püüdes pääseda vabastatud objekti kaudu, tekib viga.

Tugevate viidete tsüklid (Retain Cycles): tekivad, kui kaks või enam objekti omavad üksteisele tugevaid viiteid, takistades nende vabastamist. Lahendatakse nõrkade või mitteomandatud viidetega.

Näide:

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

    init(name: String) {
        self.name = name
        print("\(name) alustab")
    }

    deinit {
        print("\(name) lõpetab")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Kasutades nõrka viidet tsükli vältimiseks

    init(unit: String) {
        self.unit = unit
        print("Korter \(unit) alustab")
    }

    deinit {
        print("Korter \(unit) lõpetab")
    }
}

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

john!.apartment = unit4A
unit4A!.tenant = john // Siin tekib tsükkel

john = nil
unit4A = nil
// Dekonstruktorid ei kutsuta välja tsükli tõttu

Lahendus nõrga viitega:

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

    init(name: String) {
        self.name = name
        print("\(name) alustab")
    }

    deinit {
        print("\(name) lõpetab")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Kasutades nõrka viidet tsükli vältimiseks

    init(unit: String) {
        self.unit = unit
        print("Korter \(unit) alustab")
    }

    deinit {
        print("Korter \(unit) lõpetab")
    }
}

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

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

john = nil
unit4A = nil
// Mõlemad objektid vabastatakse õigesti

Mitteomandatud vs Nõrk:

  • Kasuta weak, kui viide võib muutuda nil-iks (objekt võib vabastada esimese)
  • Kasuta unowned, kui viide alati omab väärtust (objekt, millele viidatakse, on sama või pikema elutsükli)

Uduarvutused (Closures) ja tsüklid:

Uduarvutused võivad haarata objektidele viiteid, luues tugevaid tsükleid. Lahendatakse capture list-iga.

Näide:

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

    lazy var asHTML: () -> String = {
        [weak self] in // haarame `self` nõrga viitega
        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) lõpetab")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "tere, maailm")
print(paragraph!.asHTML())

paragraph = nil
// Objekt on deinitializied

Vead mälu kasutamisel:

  • Memory Graph Debugger: Xcode võimaldab visualiseerida objektide vahelisi seoseid ja tuvastada tsükleid
  • Instruments (Allocations, Leaks): jälgib mälu eraldamist ja vabastamist, otsib lekkeid.