Sobes.tech
Middle

Разкажете ни за управлението на паметта в iOS.

sobes.tech AI

Отговор от AI

iOS използва автоматично броене на референциите (ARC) за управление на паметта. ARC автоматично освобождава обектите, щом към тях няма повече референции.

Основни концепции:

  • Силна референция: Увеличава брояча на референциите на обекта. Обектът няма да бъде освободен, докато има силни референции към него.
  • Слаба референция: Не увеличава брояча на референциите. Използва се за предотвратяване на цикли на силни референции. Посочва към обект, който може да бъде освободен. Ако обектът бъде освободен, слаба референция става nil.
  • Unowned референция: Подобна на слаба, не увеличава брояча на референциите. Използва се, когато обектът, към който се отнася, има същия или по-дълъг жизнен цикъл. Unowned референцията не става nil при освобождаване на обекта. Достъпът до освободен обект чрез unowned води до изпълнителна грешка.

Цикли на силни референции (Retain Cycles): Произтичат, когато два или повече обекта имат силни референции един към друг, което пречи на освобождаването им. Решават се чрез слаби или unowned референции.

Пример за цикъл и решение:

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("Апартамент \(unit) се инициализира")
    }

    deinit {
        print("Апартамент \(unit) се деинициализира")
    }
}

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

john!.apartment = unit4A
unit4A!.tenant = john // Тук възниква цикъл

john = nil
unit4A = nil
// Методи deinit не се извикват заради цикъла

Решение с 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? // Използва се слаб референция за предотвратяване на цикъл

    init(unit: String) {
        self.unit = unit
        print("Апартамент \(unit) се инициализира")
    }

    deinit {
        print("Апартамент \(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 срещу weak:

  • Използвайте weak, когато референцията може да стане nil (обектът може да бъде освободен първи).
  • Използвайте unowned, когато референцията винаги ще има стойност (обектът, към който се отнася, има същия или по-дълъг жизнен цикъл).

Closures и цикли на референции:

Closures могат да заснемат референции към обекти, създавайки цикли на силни референции. Това се решава с 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: "hello, world")
print(paragraph!.asHTML())

paragraph = nil
// Обектът се деинициализира

Отстраняване на проблеми с паметта:

  • Memory Graph Debugger: В Xcode визуализира връзките между обектите и идентифицира цикли на силни референции.
  • Instruments (Allocations, Leaks): Инструменти за мониторинг на разпределението и освобождаването на паметта, както и за откриване на течове.