SwiftUI — это декларативный фреймворк от Apple для построения пользовательских интерфейсов на всех платформах экосистемы. Вместо императивного описания шагов разработчик объявляет, как должен выглядеть интерфейс, а SwiftUI управляет его отрисовкой и обновлением. По данным Apple Developer Documentation (2025), SwiftUI поддерживает iOS 15+, iPadOS 15+, macOS 12+, watchOS 8+ и tvOS 15+ и использует View Protocol как базовый строительный блок для всех компонентов интерфейса.
Главное
body — основа любой UI-компоненты SwiftUI, возвращающей описание экрана через композицию вьюх.SwiftUI — это декларативный фреймворк, представленный Apple в 2019 году для замены UIKit в новых проектах. Вместо того чтобы вручную создавать экземпляры UIView и добавлять их в иерархию, разработчик описывает интерфейс через структуры, соответствующие протоколу View. SwiftUI автоматически вычисляет разницу между текущим и новым состоянием и перерисовывает только изменившиеся части, используя собственный движок рендеринга.
Фреймворк написан на Swift с использованием value semantics (структуры, а не классы), что делает UI-компоненты легковесными и потокобезопасными. В отличие от UIKit, где UIViewController может весить 200+ байт из-за Objective-C runtime, SwiftUI View — это просто структура размером в несколько байт. Это особенно важно для watchOS с её ограниченной памятью.
Одно и то же описание View работает на iPhone, iPad, Mac, Apple Watch, Apple TV и Apple Vision Pro. SwiftUI адаптирует интерфейс под платформу: на iOS — сенсорные жесты, на macOS — клавиатурные комбинации, на watchOS — прокрутку Digital Crown. Это сокращает время разработки для компаний, выпускающих приложения на несколько платформ Apple, но требует дополнительной настройки для специфичных элементов каждой платформы.
В SwiftUI каждый экран — это структура, реализующая протокол View с единственным требованием: computed property body типа some View. Ключевое слово some (opaque type) скрывает конкретный тип вьюхи, позволяя SwiftUI оптимизировать рендеринг. Внутри body разработчик комбинирует готовые компоненты — Text, Image, Button, List — с помощью ViewBuilder, который собирает несколько вьюх в одну.
struct GreetingView: View {
let name: String
var var body: some View {
VStack {
Text("Привет, \(name)!")
.font(.title)
.foregroundColor(.blue)
Image(systemName: "hand.wave")
.imageScale(.large)
}
.padding()
}
}
В примере VStack (вертикальный стек) содержит Text и Image. После значения name передаётся через инициализатор структуры — так работает DI (Dependency Injection) в SwiftUI без внешних DI-контейнеров. Каждый модификатор возвращает новую вьюху с применённым изменением, не мутируя оригинал. Это возможно благодаря неизменяемости (immutability) value-типов.
ViewBuilder — это result builder, аннотированный @resultBuilder, который собирает до 10 вьюх в одну. Внутри body можно использовать if/else, switch и ForEach без дополнительных обёрток. ForEach работает с Identifiable элементами — каждой вьюхе присваивается уникальный id для корректной анимации при вставке/удалении.
В SwiftUI состояние определяет, какой контент отображается на экране. Когда состояние изменяется, SwiftUI пересоздаёт body зависимой вьюхи и сравнивает результат с предыдущим, применяя diff-алгоритм. Для хранения состояния используются property wrappers — каждый из них решает свою задачу: локальное состояние, связь с дочерней вьюхой или внешняя модель данных.
struct CounterView: View {
@State private var count = 0
var var body: some View {
VStack {
Text("Счётчик: \(count)")
Button("Увеличить") {
count += 1
}
}
}
}
class UserViewModel: ObservableObject {
@Published var name = ""
@Published var age = 0
}
@State хранит локальное простое значение (Int, String, Bool) внутри структуры View. SwiftUI выносит память из структуры в отдельное хранилище — поэтому свойство с @State можно изменять (mutate), даже если View — value-тип. @ObservableObject — для классов с @Published свойствами, изменения которых автоматически уведомляют SwiftUI о необходимости перерисовки.
@Binding создаёт двустороннюю связь с источником данных, расположенным в родительской вьюхе. Родитель передаёт $variable (projected value), ребёнок читает и записывает значение через binding. Это позволяет вынести ввод текста или переключатель в отдельную компоненту, сохранив состояние в родителе. Без @Binding каждое изменение требовало бы callback-замыкания для передачи нового значения наверх.
До iOS 16 навигация в SwiftUI строилась на NavigationView — устаревшем API со сложным поведением на iPad (split view, double column). Начиная с iOS 16, Apple рекомендует NavigationStack — упрощённую альтернативу с типа-безопасными маршрутами. Разработчик определяет enum возможных маршрутов, и NavigationStack автоматически управляет стеком экранов с поддержкой глубоких ссылок и возврата к корню.
enum Route: Hashable {
case detail(id: Int)
case settings
}
struct ContentView: View {
var var body: some View {
NavigationStack {
List {
NavigationLink("Детальный экран",
value: Route.detail(id: 42))
NavigationLink("Настройки",
value: Route.settings)
}
.navigationDestination(for: Route.self) { route in
switch route {
case .detail(let id): DetailView(id: id)
case .settings: SettingsView()
}
}
}
}
}
Маршруты типа Route.HachHashable позволяют использовать любой тип данных для передачи параметров. navigationDestination(for:destination:) связывает тип маршрута с целевой вьюхой. Преимущество перед UIKit-навигацией — перерисовка не требуется при добавлении нового маршрута: достаточно добавить case в enum и обработчик в switch. Глубокие ссылки обрабатываются через processDeepLink на NavigationStack.
Для программного перехода (после логина, таймера или ответа сервера) используется @State с NavigationLink initializer: NavigationLink(isActive: $isActive). При установке isActive = true переход выполняется без касания пользователя. Альтернатива — binding массива $path в NavigationStack: $path.append(Route.detail(id: 1)).
Modifier — это метод, возвращающий модифицированную копию вьюхи. В отличие от UIKit, где настройка свойств выполняется через мутацию существующей вьюхи, SwiftUI создаёт новое значение с применённым изменением. Цепочка модификаторов (chaining) собирает конечный интерфейс из последовательных преобразований: шрифт → отступ → цвет → тень → жест.
Apple предоставляет более 200 встроенных модификаторов. Самые частые: .font(), .foregroundColor(), .padding(), .background(), .cornerRadius(), .shadow(), .opacity(), .offset(). Порядок модификаторов важен: .padding() до .background() закрашивает область с отступом, после — только внутреннюю область. Кастомные модификаторы создаются через протокол ViewModifier.
Модификаторы можно применять условно через тернарный оператор: .foregroundColor(isError ? .red : .primary). Для анимации используется .animation(.easeInOut, value: state) — модификатор анимации привязывается к конкретному свойству состояния. При изменении этого свойства SwiftUI анимирует переход между старым и новым значением. Анимация работает с opacity, offset, scale, rotation, размером и цветом — для каждого свойства определён соответствующий AnimatableParameter.
Для кастомных анимаций доступны .transition (появление/исчезновение) и .matchedGeometryEffect (плавный переход элемента между двумя контейнерами). Последний используется для hero-анимации в списках: иконка в ячейке списка плавно превращается в крупное изображение на детальном экране.
Выбор между SwiftUI и UIKit — одна из первых дилемм iOS-разработчика. Оба фреймворка поддерживаются Apple, но решают задачу построения интерфейса принципиально разными способами: SwiftUI декларативно, UIKit императивно. Разница проявляется в управлении состоянием, навигации, производительности и совместимости.
| Аспект | SwiftUI | UIKit |
|---|---|---|
| Подход | Декларативный: что показать | Императивный: как построить |
| Состояние | Property Wrappers, автоматическая перерисовка | Вручную: reloadData, setNeedsLayout |
| Код UI | Компактный, цепочки модификаторов | Объёмный, NSCoder/Storyboard/констрейнты |
| Производительность | Высокая на iOS 17+, diff-алгоритм | Пиковая на iOS 12–16, прямой контроль |
| Минимальная версия | iOS 15+ (полная поддержка) | iOS 2+ (все версии) |
Для новых проектов с минимальной версией iOS 17 Apple рекомендует SwiftUI как основной фреймворк. UIKit остаётся необходимым для интерфейсов, требующих тонкого контроля над рендерингом (кастомные UICollectionViewLayout, сложные CAAnimation-сцены) или поддержки iOS 12–14. Многие проекты используют гибридный подход: SwiftUI через UIHostingController встраивается в UIKit-приложение, а UIViewRepresentable позволяет использовать UIKit-компоненты внутри SwiftUI-иерархии.
Часто задаваемые вопросы
Да, через UIHostingController (SwiftUI в UIKit) и UIViewRepresentable (UIKit в SwiftUI). Это гибридный подход, популярный при миграции.
С iOS 17 — полный функционал: NavigationStack, Observation framework, Swift Charts. iOS 15 — минимальный порог для production.
Самая частая причина — изменение @Published свойства на фоновой нити. ObservableObject должен отправлять изменения на main actor: @MainActor class ViewModel.
Используйте .debounce через Combine: Button.publisher(for: .tap) .debounce(for: .seconds(0.3), scheduler: RunLoop.main).
Да, через Gesture модификаторы: DragGesture, LongPressGesture, MagnificationGesture, RotationGesture. Комбинируйте через .simultaneousGesture() и .sequenced().
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также