Ответ
ARC (Automatic Reference Counting) — это механизм управления памятью в Swift и Objective-C, который автоматически подсчитывает сильные ссылки на экземпляры классов во время выполнения (runtime) и освобождает память, когда счетчик достигает нуля.
Принцип работы во время выполнения:
- Создание объекта: При вызове
init()ARC выделяет память и инициализирует счетчик ссылок (Retain Count, RC) равным 1. - Увеличение счетчика (Retain): При каждом присваивании объекта новой сильной (
strong) переменной или константе, runtime увеличивает RC.class MyClass {} var obj1: MyClass? = MyClass() // RC = 1 после init var obj2 = obj1 // RC = 2 (новая сильная ссылка) - Уменьшение счетчика (Release): Когда сильная ссылка выходит из области видимости (например, функция завершилась) или ей присваивается
nil, runtime уменьшает RC.func scope() { let temp = MyClass() // RC = 1 внутри функции } // При выходе из функции `temp` уничтожается, RC = 0 -> память освобождается - Освобождение памяти (Deallocation): В момент, когда RC становится равным 0, runtime немедленно вызывает деинициализатор
deinitи освобождает занятую объектом память.
Что делает runtime для реализации ARC:
- Вставляет вызовы
retainиreleaseв скомпилированный код в соответствующих местах. - Ведет скрытую таблицу ссылок для каждого объекта.
- При оптимизациях (например,
-O) может пропускать избыточные вызовыretain/release.
Важное следствие: ARC не управляет циклическими ссылками (когда два объекта сильно ссылаются друг на друга). Для их разрыва необходимо использовать weak (счетчик не увеличивается) или unowned ссылки.
Пример полного цикла:
class Person {
var apartment: Apartment?
deinit { print("Person freed") }
}
class Apartment {
weak var tenant: Person? // `weak` разрывает цикл
deinit { print("Apartment freed") }
}
var john: Person? = Person() // Person RC = 1
var unit4A: Apartment? = Apartment() // Apartment RC = 1
john?.apartment = unit4A // Apartment RC = 2 (сильная ссылка из john)
unit4A?.tenant = john // Person RC НЕ увеличивается, так как ссылка weak
john = nil // Person RC = 0 -> "Person freed"
// Теперь ссылка из apartment на john = nil
unit4A = nil // Apartment RC = 0 -> "Apartment freed"