TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.64K subscribers
Post #359 1.37K
🔨 Как найти и исправить зависания интерфейса в iOS.

Зависания интерфейса - один из самых раздражающих багов для пользователя и сложных для локализации для разработчика. Приложение внешне работает, но периодически замирает, не реагируя на тапы. Частая, но ошибочная реакция - грешить на слабый девайс или тяжелые анимации. В реальности корень проблемы почти всегда кроется в неправильной работе с потоками, а точнее - в блокировке главного (main) потока. Современные инструменты вроде Instruments позволяют не гадать, а точно определить, что именно и когда остановило отрисовку UI.


Определяем тип проблемы:

В Instruments открываем запись с шаблоном «Hangs» или «Time Profiler». Находим момент зависания и смотрим на загрузку CPU главного потока.

🔵CPU высокий: поток чем-то занят (тяжелые вычисления).

🔵CPU низкий: поток заблокирован и ждет (сеть, диск, lock).

Это сразу сужает круг поиска.


Включаем Thread State Trace:

Добавляем инструмент Thread State Trace и перезапускаем запись. Он покажет график состояния потоков. Нас интересует момент, когда главный поток из «Running» переходит в «Blocked».


Смотрим Call Stack:

В точке блокировки открываем стек вызовов (Call Stack). Он укажет на конкретный метод, который вызвал проблему. Часто это:

🔵Синхронная сетевая загрузка (Data(contentsOf:)).

🔵Тяжелая синхронная операция в init() вью.

🔵Блокировка мьютексом или семафором.

🔵Синхронная работа с Core Data или файлами.


Пример:

Была View со списком товаров. При скролле интерфейс замирал. Thread State Trace показал блокировку в ProductCell.init. В инициализаторе был синхронный вызов функции, которая загружала и обрабатывала превью изображения.

Решение: вынес загрузку в onAppear с использованием Task:

struct ProductCell: View {
@State private var image: UIImage?
let product: Product

var body: some View {
HStack {
if let image = image {
Image(uiImage: image)
}
Text(product.name)
}
.onAppear {
Task {
image = await loadImageAsync(from: product.imageURL)
}
}
}
}



Профилактика:

🔵Не делайте тяжелой работы в инициализаторах View.

🔵Все операции с сетью, диском или долгие вычисления - только в фоне (async/await, DispatchQueue).

🔵Регулярно прогоняйте приложение под Instruments, особенно после добавления нового функционала.


🔗 Ссылка на подробную статью


💡 Вывод:

Диагностика и устранение зависаний - это не магия, а технический процесс: записываем профиль, смотрим на состояние потока, находим проблемный метод в стеке вызовов. Инструменты дают всю нужную информацию. Главное не забывать, что основное правило для главного потока одно: он только для UI. Все остальное - в фоновые очереди.


➡️ Подписаться на канал
Мобильный трудоголик
  • 👍 18
  • ❤ 10
  • 🔥 3
  • ✍ 1
  • 🙏 1
  • 👀 1
More from @hardworkerit
  1. Oct 2, 2026👣 Архитекторы, тестировщики и кодеры. Создаем мультиагентную команду Разработка с ИИ-аген…
  2. Oct 1, 2026🔢 Работа с Picture-in-Picture в iOS. Picture-in-Picture - системная функция iOS, которая…
  3. Sep 29, 2026🔢 Управление тулбарами на iPhone Duo. На iPhone Duo элементы управления навигацией, дейст…
  4. Sep 27, 2026🔢 Новые возможности Hashable в Swift 6.4 В Swift 6.4 добавили Hashable для нескольких тип…
  5. Sep 25, 2026🔢 Приватные свойства больше не ломают memberwise инициализатор в Swift 6.4 Swift автомати…
  6. Sep 24, 2026👨‍💻 Почему разработчики ненавидят своих менеджеров. Всем привет! Сегодня хочу разобрать…
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 →