TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.64K subscribers
Post #301 1.07K
🔢 Захват ссылок в Swift: когда [weak self] становится ловушкой.

Всем привет! Наткнулся на интересную статью об отладке памяти в 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 требует не ритуала, а понимания полного контекста захвата, особенно при работе с цепочками и вложенными замыканиями.


➡️ Подписаться на канал
Мобильный трудоголик
  • 🔥 21
  • ❤ 11
  • 🤝 2
  • 👍 1
  • 🙏 1
More from @hardworkerit
  1. Oct 4, 2026🔢 SwiftUI: определение угла раскрытия iPhone Duo. В iOS 27.1 появился модификатор .onHing…
  2. Oct 2, 2026👣 Архитекторы, тестировщики и кодеры. Создаем мультиагентную команду Разработка с ИИ-аген…
  3. Oct 1, 2026🔢 Работа с Picture-in-Picture в iOS. Picture-in-Picture - системная функция iOS, которая…
  4. Sep 29, 2026🔢 Управление тулбарами на iPhone Duo. На iPhone Duo элементы управления навигацией, дейст…
  5. Sep 27, 2026🔢 Новые возможности Hashable в Swift 6.4 В Swift 6.4 добавили Hashable для нескольких тип…
  6. Sep 25, 2026🔢 Приватные свойства больше не ломают memberwise инициализатор в Swift 6.4 Swift автомати…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →