@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 е предназначен само за стойностни типове (структури, изброявания, примитиви). За референтни типове (класове) използвайте @StateObject или @ObservedObject. Ако присвоите клас на @State свойство, SwiftUI няма да може да открие промени вътре в обекта — само замяна на цялата референция.

Как работи @State под капака?

SwiftUI имплементира @State чрез вътрешния механизъм Storage. Всяко @State свойство получава специална клетка памет, съхранявана в специалния storage контейнер на изгледа. Когато се осъществи запис в wrappedValue, SwiftUI чрез didSet уведомява своя граф на зависимостите (dependency graph) за необходимостта от прерисуване.

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 за показване/скриване на модални прозорци и sheet
  • Избор на елементи — @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 поддържа масиви и речници, тъй като те са стойностни типове. При промяна на елемент от масив обаче 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също