TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.64K subscribers
Post #350 1.34K
🔢 Как не закопать производительность в глубоких иерархиях SwiftUI.

SwiftUI позиционирует себя как декларативный фреймворк, где вы просто описываете, что должно быть на экране, а система сама разбирается с обновлениями. Это удобно ровно до тех пор, пока приложение не начинает тормозить без видимых причин. Чаще всего проблема не в кривых руках, а в том, как именно вы строите дерево вьюх. Разбираемся, где SwiftUI теряет кадры и как этого избежать.


Как SwiftUI на самом деле обновляет экран:

Когда в вашей View меняется @State или другое отслеживаемое свойство, SwiftUI перезапускает вычисление body и сравнивает результат с предыдущим. Только те части интерфейса, где обнаружились различия, отправляются на рендеринг. Остальные игнорируются.

Этот механизм (диффинг) работает быстро, но у него есть цена: чем больше примитивных вьюх в body, тем больше работы алгоритму. И если вы написали одну гигантскую структуру на 200 строк, каждое изменение состояния заставит SwiftUI пройти по всей иерархии и сравнить каждый Text, каждый Image и каждую кнопку.


Главный враг - монолитное body:

Многие разработчики, пытаясь навести порядок, выносят части интерфейса в отдельные функции или вычисляемые свойства. Это делает код чище для глаз, но для SwiftUI ничего не меняет. Во время компиляции все эти вызовы схлопываются обратно в единое дерево примитивов. Производительность остается такой же, как если бы все было написано в одну строку.

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


Верный способ - отдельные структуры:

Единственный способ создать настоящие границы перерисовки - выносить части интерфейса в отдельные структуры, реализующие протокол View. Когда SwiftUI видит вложенную структуру, он сначала проверяет, изменились ли ее входные параметры. Если нет - body этой структуры даже не вызывается. Диффинг останавливается на этом уровне.


struct Counter: View {
@State private var value = 0
var body: some View {
VStack {
Button("Увеличить: \(value)") { value += 1 }
SubView()
}
}
}

struct SubView: View {
var body: some View {
Text("Данная структура не зависит от value")
}
}


В этом примере нажатие на кнопку перезапустит body у Counter, но SubView останется нетронутым. SwiftUI видит, что его параметры не изменились, и пропускает вычисления.


Коварство замыканий и Equatable:

Есть один случай, когда даже отдельные структуры могут перерисовываться без необходимости: если в них передаются замыкания. SwiftUI не умеет сравнивать замыкания по содержимому, поэтому может считать, что каждое новое замыкание - это изменение.

В таких ситуациях помогает явное указание, что вьюха поддерживает Equatable. Добавьте модификатор .equatable() и реализуйте метод ==, где явно опишите, какие поля должны влиять на перерисовку. Обратите внимание: просто подписать структуру под Equatable недостаточно, нужно еще сказать SwiftUI использовать эту информацию через .equatable().


Как отлавливать лишние перерисовки:

Самый простой способ проверить, пересоздается ли вьюха без необходимости: добавить случайный фон. Если цвета прыгают при каждом действии, значит, body вызывается чаще, чем нужно. Это хороший маркер для рефакторинга.


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


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
  • 👍 18
  • 🔥 11
  • ❤ 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 →