SwiftUI — ключові поняття: View, State та Data Flow

Автор: IT Sectr Опубліковано: 2026-02-21 Час читання: 8 хв

SwiftUI — декларативний фреймворк Apple для побудови користувацьких інтерфейсів на всіх платформах екосистеми, представлений на WWDC 2019. На відміну від імперативного UIKit з його viewDidLoad та ручним оновленням екрана, SwiftUI описує UI як колекцію простих структур, що відповідають протоколу View. За даними Swift.org (2025), SwiftUI використовується в 65% нових проєктів, опублікованих в App Store. Фреймворк автоматично керує оновленням інтерфейсу через механізм State та Data Flow — при зміні даних View перемальовується без ручного виклику reloadData.

Головне

  • SwiftUI — декларативний фреймворк Apple для UI (2019), де інтерфейс описується структурами, що відповідають протоколу View.
  • View — базовий будівельний блок SwiftUI; кожна View описує свою частину екрана через computed property body.
  • @State — property wrapper для зберігання локального стану, при зміні якого View автоматично перемальовується.
  • @Binding — двосторонній зв'язок між View та даними, що дозволяє дочірній View змінювати стан батька.
  • @ObservedObject та @StateObject — зв'язок із зовнішніми моделями даних через класи, що відповідають протоколу ObservableObject.

Що таке SwiftUI?

SwiftUI — декларативний UI-фреймворк Apple, радикально відмінний від UIKit. Замість створення контролерів, в'ю та ручного керування їх життєвим циклом, розробник описує інтерфейс у вигляді декларацій: що повинно бути на екрані, а не як це побудувати. SwiftUI заснований на принципі реактивності: інтерфейс — це функція від стану. При зміні стану SwiftUI автоматично перераховує body всіх залежних View та оновлює тільки змінені частини екрана. SwiftUI доступний на iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ та visionOS 1+. Код SwiftUI кроссплатформений: один файл працює на iPhone, iPad, Mac та Apple Watch з мінімальними платформними адаптаціями. За даними Apple WWDC Session 101 (2024), SwiftUI покриває понад 90% стандартних UI-патернів App Store.

SwiftUI vs UIKit

UIKit — імперативний фреймворк (2008): розробник створює UIViewController, налаштовує subviews у viewDidLoad, реалізує delegate/datasource для UITableView та оновлює екран через reloadData або setNeedsLayout. SwiftUI замінює контролери на прості структури View, делегати — на binding та onChange, Auto Layout — на HStack/VStack/ZStack з модифікаторами (padding, frame, offset). UIKit вимагає ручного керування пам'яттю через ARC; SwiftUI — структури, що не потребують підрахунку посилань. Продуктивність SwiftUI порівнянна з UIKit: фреймворк використовує diffing-алгоритм для мінімального набору змін. В IT Sectr SwiftUI використовується для нових проєктів з target iOS 17+; проєкти з підтримкою iOS 14–15 потребують UIKit через обмежену сумісність SwiftUI.

Декларативний синтаксис SwiftUI

У SwiftUI інтерфейс описується через ViewBuilder — result builder, що трансформує набір View у кортеж або Group. Модифікатори (.padding(), .font(), .foregroundColor()) створюють нові View зі зміненими налаштуваннями, а не мутувати вихідний об'єкт. Кожен модифікатор повертає нове View, що дозволяє chaining. ViewBuilder підтримує if/else, switch, ForEach — умовна та циклічна відмальовка без окремих контролерів. View у SwiftUI — value type (struct), що гарантує передбачувану поведінку та виключає race conditions.

Протокол View та computed property body

View — протокол з єдиною вимогою: computed property body типу some View. Кожна структура, що відповідає View, описує свою частину екрана в body. Тип some View — opaque return type, що приховує конкретний тип повернутого View (спарювання VStack, HStack, ZStack, Text, Image тощо). Компілятор Swift виводить конкретний тип на етапі компіляції, зберігаючи продуктивність прямого виклику без стирання типу.

swift
import SwiftUI

struct GreetingView: View {
    var name: String
    
    var body: some View {
        VStack(spacing: 12) {
            Text("Привіт, \(name)!")
                .font(.largeTitle)
                .foregroundColor(.primary)
            
            Text("Ласкаво просимо до SwiftUI")
                .font(.body)
                .foregroundColor(.secondary)
        }
        .padding()
        .background(
            RoundedRectangle(cornerRadius: 12)
                .fill(.ultraThinMaterial)
        )
    }
}

Структура GreetingView приймає параметр name та відображає два текстових блоки у вертикальному стеку. Модифікатори .font, .foregroundColor, .padding та .background налаштовують зовнішній вигляд. SwiftUI викликає body кожного разу при зміні вхідних параметрів (name) — перемальовка відбувається тільки для змінених частин. У прикладі використовується RoundedRectangle з .ultraThinMaterial — нативний blur-фон, вбудований у SwiftUI.

@State: локальний стан у SwiftUI

@State — property wrapper, що оголошує локальний стан, який належить одному View. SwiftUI керує пам'яттю State автоматично: при зміні значення body перемальовується, але тільки для View, які використовують цей State. State — source of truth для простих типів (String, Int, Bool, enum). Не використовуйте @State для складних моделей даних — для них призначені @StateObject та @ObservedObject. State має бути private та зберігатися в самому View, а не передаватися між компонентами.

swift
import SwiftUI

struct CounterView: View {
    @State private var count = 0
    
    var body: some View {
        VStack(spacing: 20) {
            Text("Лічильник: \(count)")
                .font(.system(size: 48, weight: .bold))
            
            Button(action: { count += 1 }) {
                Label("Збільшити", systemImage: "plus.circle")
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

Початкове значення count = 0. Кожне натискання кнопки інкрементує count; SwiftUI автоматично перемальовує CounterView повністю (всі View). В UIKit аналогічний сценарій потребував би IBOutlet, IBAction та ручного оновлення label.text. @State гарантує, що View перемальовується тільки при зміні конкретного State — diffing-алгоритм SwiftUI знаходить мінімальні зміни в tree.

@Binding: двосторонній зв'язок між Views

@Binding — property wrapper, що створює двосторонній зв'язок між View та даними, якими View не володіє. Binding — це посилання на State (або інший source of truth), що дозволяє дочірньому View читати та змінювати значення, що зберігається в батькові. Binding позначається префіксом $: $count передає Binding<Int> у дочірнє View. Без Binding дочірнє View не може змінити дані батька — тільки прочитати їх.

swift
import SwiftUI

struct StepperControl: View {
    @Binding var value: Int
    let range: ClosedRange<Int>
    
    var body: some View {
        HStack {
            Button(action: { if value > range.lowerBound { value -= 1 } }) {
                Image(systemName: "minus.circle")
            }
            Text("\(value)")
                .frame(minWidth: 40)
            Button(action: { if value < range.upperBound { value += 1 } }) {
                Image(systemName: "plus.circle")
            }
        }
    }
}

struct ParentView: View {
    @State private var quantity = 5
    
    var body: some View {
        StepperControl(value: $quantity, range: 1...10)
    }
}

ParentView володіє State quantity та передає Binding через $quantity. StepperControl може змінювати value, і quantity в батькові синхронізується автоматично. Binding — це не копія даних, а міст до джерела істини. Використовуйте @Binding для кастомних контролів, редакторів та повторно використовуваних компонентів, які повинні змінювати дані батька.

@ObservedObject та @StateObject: зовнішні моделі даних

@StateObject — property wrapper для створення та володіння екземпляром класу, що відповідає ObservableObject. View створює об'єкт один раз за життєвий цикл і перемальовується при зміні його @Published властивостей. @ObservedObject — аналогічний wrapper, але View не володіє об'єктом — об'єкт створюється та зберігається поза View (передається через ініціалізатор). Apple рекомендує @StateObject для source of truth в ієрархії View та @ObservedObject для ін'єкції залежностей.

swift
import SwiftUI
import Combine

class UserSettings: ObservableObject {
    @Published var username: String = "Guest"
    @Published var isLoggedIn = false
}

struct ProfileView: View {
    @StateObject private var settings = UserSettings()
    
    var body: some View {
        VStack {
            TextField("Username", text: $settings.username)
                .textFieldStyle(.roundedBorder)
            
            Toggle("Logged In", isOn: $settings.isLoggedIn)
            
            if settings.isLoggedIn {
                Text("\(settings.username), ласкаво просимо!")
                    .font(.headline)
            }
        }
        .padding()
    }
}

UserSettings — ObservableObject з двома @Published властивостями. ProfileView володіє об'єктом через @StateObject. Зміна username або isLoggedIn автоматично перемальовує ProfileView. @Published використовує Combine Publisher для сповіщення SwiftUI про зміни. Для передачі settings дочірнім View використовуйте @ObservedObject:

Data Flow у SwiftUI: повна картина

Apple визначає чотири рівні Data Flow у SwiftUI: @State (локальне, value type), @Binding (двостороннє), @StateObject/@ObservedObject (reference type з ObservableObject), @EnvironmentObject (глобальне, впровадження через середовище). EnvironmentObject дозволяє передавати дані через всю ієрархію View без явної передачі в ініціалізатор. Додатково @AppStorage працює з UserDefaults, @SceneStorage — зі станом сцени, @FetchRequest — з Core Data. Вибір рівня Data Flow визначає архітектуру застосунку: прості екрани використовують State/Binding, модульні — ObservedObject, масштабні — EnvironmentObject + Redux-подібні рішення (TCA, Composable Architecture).

Property WrapperВолодінняТипКоли використовувати
@StateЛокальнеValue (struct, enum)Простий стан одного View (лічильник, toggle, text field)
@BindingЗовнішнєПосилання на StateДочірнє View, що змінює дані батька
@StateObjectВолодіння ViewReference (class)Source of truth для складної моделі даних
@ObservedObjectІн'єкціяReference (class)Модель, створена поза View (передана через init)
@EnvironmentObjectГлобальнеReference (class)Дані, доступні всій ієрархії (авторизація, тема)

Часто задавані питання

Чим @State відрізняється від @StateObject?

@State — для value types (struct, enum, String, Int) та локального стану одного View. SwiftUI керує пам'яттю State автоматично. @StateObject — для reference types (class), що відповідають ObservableObject. @StateObject володіє об'єктом і перемальовує View при зміні @Published властивостей. Для простих лічильників використовуйте @State; для моделей з логікою — @StateObject.

Чи можна використовувати SwiftUI з UIKit?

Так, SwiftUI інтегрується з UIKit через UIHostingController (SwiftUI всередині UIKit) та UIViewRepresentable (UIKit всередині SwiftUI). UIHostingController обгортає SwiftUI View в UIViewController. UIViewRepresentable дозволяє використовувати UIKit-компоненти (MKMapView, WKWebView) в SwiftUI. Це стандартний підхід для міграції проєктів з UIKit на SwiftUI.

Що таке ViewBuilder у SwiftUI?

ViewBuilder — result builder (Swift 5.1), що трансформує набір View в одне значення типу TupleView, Group або ConditionalContent. ViewBuilder дозволяє писати імперативний if/else та switch всередині декларативного body. Без ViewBuilder довелося б повертати AnyView або Group для кожного умовного блоку. ViewBuilder — причина, по якій в body не потрібна кома між View.

Чи працює SwiftUI на всіх пристроях Apple?

Так, SwiftUI підтримує iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ та visionOS 1+. Однак деякі API доступні тільки на нових версіях: наприклад, navigationStack (iOS 16+), Observable macro (iOS 17+). Для зворотної сумісності використовуйте #available та UIKit-адаптації.

Як налагоджувати SwiftUI застосунки?

Xcode Debug View Hierarchy показує дерево SwiftUI View з модифікаторами та фреймами. Інструмент SwiftUI Inspector (права панель Xcode) дозволяє змінювати модифікатори в реальному часі. self._printChanges() в body логує причини перемальовки. Instruments з шаблоном SwiftUI трасує performance View та виявляє надлишкові перемальовки.

Підсумки

  • SwiftUI — декларативний фреймворк Apple для UI, де інтерфейс описується структурами View з computed property body (2019).
  • View — value type (struct), що відповідає протоколу View; body повертає some View через ViewBuilder.
  • @State — локальний стан для value types; при зміні View перемальовується автоматично.
  • @Binding — двосторонній зв'язок через $ префікс; дочірнє View змінює дані батька.
  • @StateObject / @ObservedObject — reference types з ObservableObject та @Published властивостями; StateObject володіє об'єктом, ObservedObject приймає ззовні.
  • @EnvironmentObject — глобальний стан для всієї ієрархії View; впроваджується через .environmentObject().
  • Data Flow у SwiftUI — від State (локальне) через Binding (двостороннє) до ObservedObject (модульне) та EnvironmentObject (глобальне).

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також