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

Как работает ARC (Automatic Reference Counting) в Swift?

1.0 Junior🔥 82 комментариев
#CI/CD и инструменты разработки#Soft Skills и карьера#SwiftUI

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

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

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

Как работает ARC (Automatic Reference Counting) в Swift

ARC (Automatic Reference Counting) — это механизм автоматического подсчёта ссылок, встроенный в компилятор Swift для управления памятью в куче (heap). Он отслеживает количество сильных ссылок на каждый экземпляр класса и автоматически освобождает память, когда счётчик становится равным нулю. Это избавляет разработчика от ручного управления памятью, как в языках с ручным управлением (например, C).

Основные принципы работы ARC

  1. Подсчёт ссылок: Каждый раз, когда создаётся сильная ссылка на объект, счётчик увеличивается на единицу. Когда ссылка выходит из области видимости или ей присваивается nil, счётчик уменьшается.
  2. Освобождение памяти: Как только счётчик достигает нуля, ARC автоматически вызывает деинициализатор (deinit) и освобождает память.
  3. Работа только с ссылочными типами: ARC применяется исключительно к экземплярам классов (ссылочным типам). Для структур и перечислений (типов-значений) ARC не используется, так как они копируются и живут в стеке.

Пример базовой работы ARC:

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) создан")
    }
    deinit {
        print("\(name) удалён")
    }
}

var person1: Person?
var person2: Person?
var person3: Person?

person1 = Person(name: "Алексей") // Счётчик = 1
person2 = person1 // Счётчик = 2
person3 = person1 // Счётчик = 3

person1 = nil // Счётчик = 2
person2 = nil // Счётчик = 1
person3 = nil // Счётчик = 0, вызывается deinit

Проблемы циклических ссылок и их решение

Основная сложность при использовании ARC — циклические ссылки, когда два или более объекта сильно ссылаются друг на друга, предотвращая уменьшение счётчика до нуля и вызывая утечки памяти. Swift предлагает три механизма для их предотвращения:

  1. Слабые ссылки (weak references): Объявляются ключевым словом weak. Они не увеличивают счётчик ссылок и автоматически становятся nil, когда объект, на который они ссылаются, освобождается. Используются, когда один объект может пережить другой (например, делегаты).
class Apartment {
    weak var tenant: Person? // Слабая ссылка
}
  1. Бессвязные ссылки (unowned references): Объявляются ключевым словом unowned. Как и слабые, не увеличивают счётчик, но предполагается, что они всегда ссылаются на существующий объект. Используются, когда объекты имеют одинаковое время жизни.
class Customer {
    var card: CreditCard?
}

class CreditCard {
    unowned let owner: Customer // Бессвязная ссылка
}
  1. Захват списков в замыканиях: Замыкания в Swift также являются ссылочными типами и могут создавать циклические ссылки. Решение — использовать списки захвата (capture lists) с weak или unowned.
class DataProcessor {
    var completion: (() -> Void)?

    func processData() {
        completion = { [weak self] in // Захват self как слабой ссылки
            self?.handleCompletion()
        }
    }
}

Оптимизации ARC

Swift использует дополнительные оптимизации для уменьшения накладных расходов ARC:

  • ARC сокращает количество операций со счётчиком в некоторых контекстах (например, внутри функций).
  • Встроенные (inline) ссылки могут использоваться для значений с коротким временем жизни.
  • Компилятор анализирует время жизни объектов, что позволяет иногда полностью избежать подсчёта ссылок.

Практические рекомендации

  • Используйте weak для делегатов и обратных вызовов.
  • Применяйте unowned только при уверенности в существовании объекта.
  • Всегда анализируйте замыкания на предмет циклических захватов.
  • Инструменты профилирования (например, Instruments в Xcode) помогают находить утечки памяти.

ARC в Swift представляет собой мощный и эффективный механизм управления памятью, который, при правильном использовании, полностью исключает необходимость ручного управления памятью, сохраняя при этом высокую производительность приложений.