Назад к вопросам
Middle
82
questionbank

Что такое автоматический подсчет ссылок?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Автоматический подсчет ссылок (Automatic Reference Counting, ARC) - это механизм управления памятью в Swift и Objective-C, который автоматически отслеживает и освобождает память, выделенную для объектов. Каждый экземпляр класса имеет счетчик ссылок, который увеличивается при создании сильной ссылки на объект и уменьшается при ее удалении. Когда счетчик ссылок достигает нуля, ARC автоматически деаллоцирует объект и освобождает занимаемую им память.

ARC предотвращает утечки памяти и двойное освобождение, упрощая управление памятью по сравнению с ручным управлением (как в Objective-C без ARC).

Существует три типа ссылок:

  1. Strong (Сильная): Увеличивает счетчик ссылок объекта. Является типом ссылки по умолчанию.
  2. Weak (Слабая): Не увеличивает счетчик ссылок. Используется для предотвращения циклов сильных ссылок, когда два объекта сильно ссылаются друг на друга. Слабая ссылка становится nil, если объект, на который она указывает, деаллоцирован. Определяется с помощью ключевого слова weak.
  3. Unowned (Бесхозная): Не увеличивает счетчик ссылок и всегда имеет значение. Используется, когда известно, что ссылка всегда будет указывать на объект, пока объект существует. В отличие от weak, бесхозная ссылка не становится nil и может вызвать сбой, если попытаться получить доступ к объекту после его деаллокации. Определяется с помощью ключевого слова unowned.

Пример цикла сильных ссылок:

class Human {
    let name: String
    var apartment: Apartment? // Сильная ссылка на Optional Apartment
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

class Apartment {
    let unit: String
    var tenant: Human? // Сильная ссылка на Optional Human
    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) is being initialized")
    }
    deinit {
        print("Apartment \(unit) is being deinitialized")
    }
}

var john: Human?
var unit4A: Apartment?

john = Human(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

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

john = nil
unit4A = nil
// Ни "John Appleseed is being deinitialized", ни "Apartment 4A is being deinitialized" не будет выведено из-за цикла сильных ссылок

Решение проблемы цикла сильных ссылок с использованием weak:

class Human {
    let name: String
    var apartment: Apartment?
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Human? // Слабая ссылка
    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) is being initialized")
    }
    deinit {
        print("Apartment \(unit) is being deinitialized")
    }
}

var john: Human?
var unit4A: Apartment?

john = Human(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

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

john = nil // John деаллоцируется, так как его счетчик ссылок становится 0
unit4A = nil // Apartment деаллоцируется, так как его счетчик ссылок становится 0