Sobes.tech
Middle

Реците нам о управљању меморијом у iOS.

sobes.tech АИ

Одговор од АИ

iOS koristi automatsko brojanje referenci (ARC) za upravljanje memorijom. ARC automatski oslobađa objekte čim na njih prestanu da se odnose reference.

Glavni koncepti:

  • Jake Reference: Povećava brojač referenci objekta. Objekat neće biti oslobođen dok postoje jake reference na njega.
  • Slabe Reference: Ne povećava brojač referenci. Koristi se za sprečavanje ciklusa jakih referenci. Referira na objekat koji može biti oslobođen. Ako je objekat oslobođen, slaba referenca postaje nil.
  • Unowned Referenca: Slično slabo, ne povećava brojač referenci. Koristi se kada objekat na koji se referiše ima isti ili duži životni vek. Unowned referenca ne postaje nil pri oslobađanju objekta. Pristup oslobođenom objektu putem unowned izaziva grešku u izvršenju.

Ciklus jakih referenci (Retain Cycles): Javljaju se kada dva ili više objekata imaju jake reference jedan na drugog, sprečavajući njihovo oslobađanje. Rešavaju se pomoću slabih ili unowned referenci.

Primer ciklusa i rešenje:

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

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

    deinit {
        print("\(name) se deinitializuje")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Koristi se slab referenca za sprečavanje ciklusa

    init(unit: String) {
        self.unit = unit
        print("Stan \(unit) se inicijalizuje")
    }

    deinit {
        print("Stan \(unit) se deinitializuje")
    }
}

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

john!.apartment = unit4A
unit4A!.tenant = john // Ovde nastaje ciklus

john = nil
unit4A = nil
// Metode deinit nisu pozvane zbog ciklusa

Rešenje pomoću slabog odnosa:

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

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

    deinit {
        print("\(name) se deinitializuje")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person? // Koristi se slab referenca za sprečavanje ciklusa

    init(unit: String) {
        self.unit = unit
        print("Stan \(unit) se inicijalizuje")
    }

    deinit {
        print("Stan \(unit) se deinitializuje")
    }
}

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

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

john = nil
unit4A = nil
// Oba objekta se pravilno deinitializuju

unowned vs weak:

  • Koristi weak kada referenca može postati nil (objekat može biti prvi oslobođen).
  • Koristi unowned kada referenca uvek ima vrednost (objekat na koji se odnosi ima isti ili duži životni vek).

Closures i ciklusi referenci:

Closures mogu uhvatiti reference na objekte, stvarajući cikluse jakih referenci. To se rešava pomoću capture liste.

Primer:

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

    lazy var asHTML: () -> String = {
        [weak self] in // Slaba referenca na 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) se deinitializuje")
    }
}

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

paragraph = nil
// Objekat se deinitializuje

Dijagnostika problema sa memorijom:

  • Memory Graph Debugger: U Xcode omogućava vizualizaciju veza između objekata i identifikaciju ciklusa jakih referenci.
  • Instruments (Allocations, Leaks): Alati za praćenje dodeljivanja i oslobađanja memorije, kao i za pronalaženje curenja.