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 з єдиною вимогою: обчислювана властивість 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()
}
}
}
}
}
Маршрути, що відповідають Hashable, дозволяють використовувати будь-який тип даних для передачі параметрів. navigationDestination(for:destination:) пов'язує тип маршруту з цільовою в'юхою. Перевага перед UIKit-навігацією — перемальовування не потрібне при додаванні нового маршруту: достатньо додати case в enum та обробник у switch. Глибокі посилання обробляються через processDeepLink на NavigationStack.
Для програмного переходу (після логіну, таймера або відповіді сервера) використовується @State з ініціалізатором NavigationLink: NavigationLink(isActive: $isActive). При встановленні isActive = true перехід виконується без дотику користувача. Альтернатива — зв'язування масиву $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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.