@State — призначення та використання у SwiftUI

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

@State — це Property Wrapper у SwiftUI для керування локальним станом в межах одного представлення. SwiftUI автоматично перемальовує представлення при кожній зміні властивості @State, роблячи інтерфейс реактивним без ручних викликів оновлення. Згідно з Apple Developer Documentation (2025), @State рекомендується для простих типів і структур, що належать одному представленню. @State — це найпростіший спосіб додати інтерактивність до інтерфейсу SwiftUI.

Головне

  • @State — Property Wrapper для локального стану, що належить одному представленню
  • Автоматичне оновлення — SwiftUI перезапускає body при зміні властивості @State
  • Прості типи — @State підходить для String, Int, Bool, enum і структур
  • Не передавати дочірнім представленням — для змін із дочірніх компонентів використовуйте @Binding
  • private — властивості @State завжди оголошуються з модифікатором private

Що таке @State у SwiftUI?

@State — це Property Wrapper, вбудований у SwiftUI, який дозволяє представленню зберігати та відстежувати власний стан. Коли значення @State змінюється, SwiftUI автоматично перемальовує представлення, викликаючи властивість body заново. Це основа реактивного програмування у SwiftUI: розробник оголошує стан, а фреймворк бере на себе синхронізацію інтерфейсу.

@State створює область зберігання в купі, керовану SwiftUI. Ця область персистентна — вона переживає повторні ініціалізації структури представлення, які відбуваються при кожному рендері. SwiftUI використовує ідентифікатор представлення (згенерований на основі позиції в ієрархії) для прив'язки властивості @State до конкретного представлення. Завдяки цьому стан не скидається при оновленні батьківського представлення.

Важливе обмеження: @State призначений лише для Value-типів (структур, переліків, примітивів). Для посилальних типів (класів) використовуйте @StateObject або @ObservedObject. Якщо присвоїти клас властивості @State, SwiftUI не зможе виявити зміни всередині об'єкта — лише заміну посилання повністю.

Як працює @State всередині?

SwiftUI реалізує @State через внутрішній механізм Storage. Кожна властивість @State отримує виділену комірку пам'яті, яка зберігається у спеціальному контейнері зберігання представлення. Коли відбувається запис у wrappedValue, SwiftUI через didSet повідомляє свій граф залежностей про необхідність перемалювання.

swift
struct ContentView: View {
    @State private var name: String = "User"
    @State private var isLoggedIn: Bool = false

    var body: some View {
        VStack {
            Text("Привіт, \(name)")
            Button(isLoggedIn ? "Вийти" : "Увійти") {
                isLoggedIn.toggle()
            }
        }
    }
}

У прикладі дві властивості @State: name (String) і isLoggedIn (Bool). При виклику isLoggedIn.toggle() SwiftUI позначає ContentView як такий, що потребує оновлення, і перезапускає body у наступному циклі рендера. Ключовий момент: властивості @State завжди оголошуються з модифікатором private — це сигнал, що стан належить виключно поточному представленню і не повинен змінюватися ззовні напряму.

Для спостереження за змінами SwiftUI використовує CurrentValueSubject з Combine. Кожна властивість @State створює прихованого видавця, який повідомляє систему при кожній зміні. Це дозволяє SwiftUI перемальовувати лише мінімально необхідний набір представлень, уникаючи повного оновлення ієрархії.

Коли використовувати @State у проєкті

@State оптимальний для простих локальних станів: текстові поля пошуку, булеві прапорці для модальних вікон, перемикачі налаштувань, лічильники, вибрані елементи списку. Якщо значення використовується лише в одному представленні та його дочірніх компонентах (через @Binding), @State — правильний вибір. Для станів, які повинні переживати закриття представлення (наприклад, дані форми), @State також підходить, поки представлення залишається в ієрархії.

  • Текстові поля — @State для зберігання введеного тексту в TextField
  • Булеві прапорці — @State для показу/приховування модальних вікон і листів
  • Вибір елементів — @State для відстеження вибраної вкладки або рядка
  • Лічильники — @State для числових значень з інкрементом/декрементом
  • Проміжні обчислення — @State для кешування результатів всередині представлення

Не використовуйте @State для глобальних станів застосунку, кешування мережевих даних або об'єктів, які використовуються на кількох екранах. Для цих цілей призначені @StateObject і @EnvironmentObject. Також @State не підходить для зберігання великих обсягів даних — кожного разу при зміні буде перемальовуватися все представлення.

@State і @Binding: спільна робота

@Binding — це міст між @State у батьківському представленні та дочірнім представленням, якому потрібно змінювати цей стан. Батько оголошує @State, а дочірній компонент отримує Binding через проекцію $. Зміна Binding у дочірньому представленні автоматично оновлює @State у батькові — і навпаки. Це забезпечує однонаправлений потік даних з можливістю зворотного зв'язку.

swift
struct ParentView: View {
    @State private var text: String = ""

    var body: some View {
        ChildView(text: $text)
    }
}

struct ChildView: View {
    @Binding var text: String

    var body: some View {
        TextField("Enter text", text: $text)
    }
}

У лістингу ParentView володіє @State text, а ChildView отримує $text як Binding. TextField всередині ChildView прив'язується до цього Binding через text: $text. Коли користувач друкує в TextField, значення змінюється в ChildView через Binding, що викликає оновлення @State у ParentView. Обидва представлення перемальовуються з новим значенням.

Типові помилки при роботі з @State

Найпоширеніша помилка — присвоєння класу властивості @State. Якщо написати @State var model = MyClass(), SwiftUI не зможе відстежити зміни властивостей всередині класу — лише заміну самого об'єкта. Для класів завжди використовуйте @StateObject. Друга поширена проблема — оголошення @State без модифікатора private, що порушує принцип інкапсуляції стану.

Передача @State напряму в дочірнє представлення без $ — ще одна типова помилка. Якщо передати TextField(text: text) замість TextField(text: $text), дочірній компонент отримає просто рядок, а не Binding. Зміна тексту в TextField не буде синхронізована з батьківським @State. Завжди використовуйте проекцію $ для передачі Binding.

Третя помилка — множинні властивості @State для пов'язаних даних. Якщо кілька значень логічно утворюють єдине ціле (наприклад, поля форми), об'єднайте їх в одну структуру з єдиним @State. Це спрощує передачу стану дочірнім представленням і зменшує кількість окремих тригерів оновлення.

Приклади використання @State у SwiftUI

@State застосовується в більшості проєктів SwiftUI для базової інтерактивності. Розглянемо приклад форми входу, де @State керує текстовими полями та станом завантаження. Такий патерн зустрічається в кожному застосунку — від простих нотаток до складних корпоративних рішень.

swift
struct LoginView: View {
    @State private var email: String = ""
    @State private var password: String = ""
    @State private var isLoading: Bool = false
    @State private var errorMessage: String?

    var body: some View {
        Form {
            TextField("Email", text: $email)
            SecureField("Password", text: $password)
            Button("Увійти") {
                login()
            }.disabled(isLoading)
        }
    }

    private func login() {
        isLoading = true
        // Виконати мережевий запит
    }
}

У прикладі чотири властивості @State: email і password для полів форми, isLoading для індикації завантаження та errorMessage для відображення помилок. Кожна властивість незалежно керує своєю частиною інтерфейсу. При зміні isLoading кнопка автоматично блокується через disabled(isLoading) — без ручного оновлення UI.

Часті запитання

Чому @State оголошується з private?

@State призначений для локального стану конкретного представлення. Модифікатор private гарантує, що інші компоненти не змінять його напряму, порушуючи інкапсуляцію. Для зовнішнього доступу використовуйте проекцію $.

Чи може @State містити масив або словник?

Так, @State підтримує масиви та словники, оскільки це Value-типи. Однак при зміні елемента масиву SwiftUI перемальовує все представлення. Для великих списків ефективніше використовувати @StateObject з @Published.

Що станеться при присвоєнні nil властивості @State з Optional-типом?

@State коректно працює з Optional-типами. При присвоєнні nil SwiftUI виявляє зміну та перемальовує представлення. Це зручно для станів errorMessage: String?, де nil означає відсутність помилки.

Як @State поводиться при повторній появі представлення?

@State зберігає значення, поки представлення залишається в ієрархії. Якщо представлення видаляється з ієрархії та додається знову, @State ініціалізується заново зі значенням за замовчуванням. Для персистентності використовуйте @AppStorage.

Чи можна анімувати зміни @State?

Так, оберніть зміну в withAnimation: withAnimation(.easeInOut) { isExpanded.toggle() }. SwiftUI анімує перехід між старим і новим станом інтерфейсу з указаним типом анімації.

Підсумки

  • @State — Property Wrapper для локального стану одного представлення, автоматично оновлює інтерфейс
  • Підходить для простих типів: String, Int, Bool, а також структур і enum
  • Не підходить для посилальних типів (класів) — використовуйте @StateObject
  • Завжди private — стан не повинен змінюватися ззовні напряму
  • Проекція $ — створює Binding для передачі права зміни дочірнім представленням
  • Кілька @State в одному представленні — нормальна практика для незалежних станів
  • withAnimation — дозволяє анімувати зміни властивостей @State

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

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

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

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