Как обнаружить retain cycle (цикл сильных ссылок) в iOS-приложении?

«Как обнаружить retain cycle (цикл сильных ссылок) в iOS-приложении?» — вопрос из категории Управление памятью, который задают на 22% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Retain cycle возникает, когда два или более объекта удерживают друг друга через strong-ссылки, предотвращая их освобождение ARC. Методы обнаружения:

1. Инструменты Xcode:

  • Debug Memory Graph (кнопка с графом в нижней панели отладчика). Показывает визуальный граф объектов в памяти. Циклы отображаются как замкнутые связи. Позволяет сразу увидеть, какие объекты участвуют в цикле.
  • Instruments → Leaks. Запустите профилирование для обнаружения утечек памяти в runtime.

2. Профилактика в коде:

  • Всегда используйте [weak self] или [unowned self] в замыканиях, когда self может удерживать это замыкание.

    class DataLoader {
    var onComplete: (() -> Void)?
    
    func loadData(completion: @escaping () -> Void) {
        self.onComplete = completion
        // ... загрузка
    }
    
    func setupHandler() {
        loadData { [weak self] in // Разрываем потенциальный цикл
            self?.handleData()
        }
    }
    }
  • Для паттерна делегата всегда объявляйте свойство делегата как weak.
    protocol MyDelegate: AnyObject { ... }
    class MainClass {
    weak var delegate: MyDelegate?
    }

3. Дополнительная настройка:

  • Включение Zombie Objects (в схеме → Diagnostics) помогает отловить обращение к уже освобождённому (deallocated) объекту, что может быть косвенным признаком проблем с памятью.