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

Сколько объектов нужно для Reference Cycle?

1.8 Middle🔥 231 комментариев
#Управление памятью

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

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

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

Как создать циклическую ссылку (Reference Cycle)

Для создания циклической ссылки, или цикла сильных ссылок, в Swift необходимо минимум два объекта, которые хранят друг друга в свойствах с сильной ссылкой (strong reference). Однако важно понимать, что циклическая ссылка возникает не из-за количества объектов, а из-за взаимного владения (mutual ownership), когда каждый объект сохраняет сильную ссылку на другой, предотвращая их освобождение из памяти.

Базовый пример с двумя объектами

Рассмотрим классический пример с двумя классами, Person и Apartment, где каждый имеет сильную ссылку на другой:

class Person {
    let name: String
    var apartment: Apartment? // Сильная ссылка на Apartment

    init(name: String) {
        self.name = name
    }
}

class Apartment {
    let unit: String
    var tenant: Person? // Сильная ссылка на Person

    init(unit: String) {
        self.unit = unit
    }
}

Если создать экземпляры и связать их, возникает цикл:

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

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

После этого даже если обнулить внешние ссылки, объекты остаются в памяти:

john = nil
unit4A = nil
// Объекты Person и Apartment НЕ освобождаются из-за цикла

Важные особенности циклических ссылок

  • Минимальное количество: Технически цикл возможен с двумя объектами, как показано выше. Но могут участвовать и больше объектов, образуя цепочку взаимных ссылок (например, A → B → C → A).
  • Типы ссылок: Циклы возникают только с сильными ссылками (strong). Использование weak (weak) или unowned (unowned) ссылок предотвращает их.
  • Контекст: Чаще циклы встречаются между объектами и closures, когда захват (capture) self в замыкании создает сильную ссылку, и объект также хранит это замыкание.

Пример цикла с closure

Цикл может возникнуть даже с одним объектом, если он хранит closure, который захватывает self:

class NetworkManager {
    var onComplete: (() -> Void)? // Closure хранится как свойство

    func fetchData() {
        // Closure захватывает self сильной ссылкой
        onComplete = { 
            self.processData() // Это создает сильную ссылку на self
        }
    }

    private func processData() { }
}

Здесь NetworkManager владеет onComplete, а onComplete владеет self, образуя цикл.

Как предотвратить циклы

  • Weak references: Используйте weak для ссылок, которые не должны владеть объектом (например, weak var tenant: Person? в Apartment).
  • Unowned references: Используйте unowned когда объект гарантированно существует, но не должен владеть (например, для ссылок на родительские объекты).
  • Capture lists в closures: При захвате self в closure указывайте [weak self] или [unowned self].
func fetchData() {
    onComplete = { [weak self] in
        self?.processData()
    }
}

Вывод

Минимально необходимо два объекта с взаимными сильными ссылками для создания классической циклической ссылки. Однако в практике Swift циклы также часто возникают с одним объектом и его closure. Ключевое решение — использование weak или unowned ссылок, которые позволяют системе автоматического подсчета ссылок (ARC) корректно освобождать память. Понимание этих механизмов критически важно для разработки стабильных и эффективных iOS приложений.