Всем привет! Наткнулся на интересную статью об отладке памяти в iOS. Автор разбирает реальный кейс, где мелкий UI-баг оказался верхушкой айсберга серьезной проблемы.
С чего все началось:
Пользователи жаловались на странное поведение: при переходе по пуш-уведомлению анимация открытия экрана срабатывала дважды. Казалось бы, мелочь, но именно с таких мелочей часто начинаются интересные расследования.
Расследование по шагам:
Автор методично искал причину. Сначала: классические print-ы по всему стеку вызовов. Оказалось, что обработчик deep link вызывался дважды, и что важнее: от двух разных экземпляров координатора в памяти.
Ключевая зацепка: проблема воспроизводилась только после выхода и повторного входа в аккаунт. Это намекало, что старые объекты не убирались из памяти.
Масштаб проблемы:
Используя Memory Graph Debugger, автор обнаружил шокирующую вещь: в системе оставались жить целые копии части приложения, со всеми координаторами, сервисами и вью-моделями. Каждый перелогин добавлял новый слой в память.
Найденный виновник:
Проблема скрывалась в, казалось бы, корректном коде:
.sink(receiveValue: {
Task { [weak self] in // weak здесь не спасает!
// логика
}
})
Ошибка была в том, что [weak self] стоял во внутреннем замыкании Task, в то время как внешнее замыкание .sink захватывало self сильно по умолчанию.
Решение в одну строку:
Исправление оказалось минимальным, но критически важным:
.sink(receiveValue: { [weak self] in // weak должен быть здесь!
Task {
// логика
}
})
💡 Вывод:
Эта история наглядно показывает, как механическая, но невнимательная расстановка [weak self] может создать иллюзию безопасности, скрывая реальную утечку памяти. Мы часто действуем по шаблону, добавляя слабый захват в асинхронные блоки, забывая, что корень проблемы может находиться уровнем выше - в замыкании, которое инициирует эту асинхронную операцию. Ключевой урок здесь в том, что борьба с retain cycles требует не ритуала, а понимания полного контекста захвата, особенно при работе с цепочками и вложенными замыканиями.
➡️ Подписаться на канал
Мобильный трудоголик