← Назад к вопросам

Что делает ARC в Run Time?

1.0 Junior🔥 271 комментариев
#Управление памятью#Язык Swift

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

ARC (Automatic Reference Counting) в Runtime

ARC — это автоматический механизм управления памятью в Swift и Objective-C. Вместо сборщика мусора, ARC отслеживает и автоматически освобождает память через подсчёт ссылок.

Как работает подсчёт ссылок

Когда объект создаётся, его reference count = 1. При каждом новом присваивании переменной счётчик увеличивается на 1. Когда переменная выходит из scope или переприсваивается, счётчик уменьшается на 1. Когда счётчик достигает 0, объект немедленно освобождается из памяти.

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("Person \(name) init")
    }
    deinit {
        print("Person \(name) deinit")
    }
}

// Демонстрация ARC
var person1: Person? = Person(name: "Alice") // refCount = 1
var person2 = person1  // refCount = 2
person1 = nil         // refCount = 1
person2 = nil         // refCount = 0 → deinit вызывается

Strong vs Weak ссылки

Strong ссылка — увеличивает reference count. Это используется по умолчанию. Если все ссылки на объект strong, объект остаётся в памяти.

Weak ссылка — НЕ увеличивает reference count. Используется для избежания retain cycles. Weak ссылка автоматически становится nil когда объект деинициализируется.

class Parent {
    let name: String
    var child: Child?
    
    init(name: String) {
        self.name = name
    }
    
    deinit {
        print("Parent \(name) deinitialized")
    }
}

class Child {
    let name: String
    weak var parent: Parent?  // Weak чтобы избежать цикла
    
    init(name: String) {
        self.name = name
    }
    
    deinit {
        print("Child \(name) deinitialized")
    }
}

// Без weak была бы утечка памяти (retain cycle)
var parent: Parent? = Parent(name: "John")
var child: Child? = Child(name: "Jane")
parent?.child = child
child?.parent = parent

parent = nil  // Parent деинициализируется
child = nil   // Child деинициализируется

Unowned ссылки

Unowned похожа на weak, но не опциональна. Используется когда дочерний объект НИКОГДА не будет существовать без родителя.

class CreditCard {
    let number: String
    unowned let owner: Person  // owner никогда не null
    
    init(number: String, owner: Person) {
        self.number = number
        self.owner = owner
    }
}

let person = Person(name: "Bob")
let card = CreditCard(number: "1234", owner: person)
// person всегда существует пока существует card

Capture Lists в Closures

Closure'ы могут создавать retain cycle'ы, если захватывают self. Используй capture list для управления::

class ViewController: UIViewController {
    var name = "ViewController"
    
    func setupButton() {
        button.addAction(UIAction { [weak self] _ in
            // weak self избегает retain cycle
            guard let self else { return }
            print(self.name)
        }, for: .touchUpInside)
    }
}

Runtime процесс

  1. Compile time — компилятор вставляет retain и release вызовы
  2. Runtime — Objective-C runtime отслеживает refCount для каждого объекта
  3. Deallocation — когда refCount = 0, вызывается deinit и память освобождается

Это означает, что в отличие от GC, память освобождается НЕМЕДЛЕННО, что крайне важно для мобильных устройств с ограниченными ресурсами.

Что делает ARC в Run Time? | PrepBro