@State je Property Wrapper ve SwiftUI pro správu lokálního stavu v rámci jednoho zobrazení. SwiftUI automaticky překresluje zobrazení při každé změně vlastnosti @State, čímž činí rozhraní reaktivním bez ručního volání aktualizací. Podle Apple Developer Documentation (2025) je @State doporučen pro jednoduché typy a struktury patřící jednomu zobrazení. @State je nejjednodušší způsob, jak přidat interaktivitu do rozhraní SwiftUI.
Hlavní body
@State je vestavěný Property Wrapper ve SwiftUI, který umožňuje zobrazení ukládat a sledovat vlastní stav. Když se hodnota @State změní, SwiftUI automaticky překreslí zobrazení a znovu zavolá vlastnost body. To je základ reaktivního programování ve SwiftUI: vývojář deklaruje stav a framework přebírá synchronizaci rozhraní.
@State vytváří úložný prostor na haldě spravovaný SwiftUI. Tento prostor je perzistentní — přežívá opakované inicializace struktury zobrazení, ke kterým dochází při každém vykreslení. SwiftUI používá identifikátor zobrazení (generovaný na základě pozice v hierarchii) k propojení vlastnosti @State s konkrétním zobrazením. Díky tomu se stav neresusetuje při aktualizaci nadřazeného zobrazení.
Důležité omezení: @State je určen pouze pro hodnotové typy (struktury, výčty, primitiva). Pro referenční typy (třídy) použijte @StateObject nebo @ObservedObject. Pokud přiřadíte třídu vlastnosti @State, SwiftUI nebude schopen detekovat změny uvnitř objektu — pouze nahrazení celé reference.
SwiftUI implementuje @State prostřednictvím interního mechanismu Storage. Každá vlastnost @State získá vyhrazenou paměťovou buňku uloženou ve speciálním storage kontejneru zobrazení. Když dojde k zápisu do wrappedValue, SwiftUI prostřednictvím didSet upozorní svůj graf závislostí (dependency graph) na nutnost překreslení.
struct ContentView: View {
@State private var name: String = "User"
@State private var isLoggedIn: Bool = false
var body: some View {
VStack {
Text("Ahoj, \(name)")
Button(isLoggedIn ? "Odhlásit" : "Přihlásit") {
isLoggedIn.toggle()
}
}
}
}
V příkladu jsou dvě vlastnosti @State: name (String) a isLoggedIn (Bool). Při zavolání isLoggedIn.toggle() SwiftUI označí ContentView jako vyžadující aktualizaci a znovu spustí body v dalším cyklu vykreslování. Klíčový bod: vlastnosti @State se vždy deklarují s modifikátorem private — to je signál, že stav patří výhradně aktuálnímu zobrazení a neměl by být měněn zvenčí přímo.
Pro sledování změn používá SwiftUI CurrentValueSubject z Combine. Každá vlastnost @State vytváří skrytého vydavatele, který upozorňuje systém při každé změně. To umožňuje SwiftUI překreslovat pouze minimálně nezbytnou sadu zobrazení a vyhnout se úplné aktualizaci hierarchie.
@State je optimální pro jednoduché lokální stavy: textová pole pro vyhledávání, boolean příznaky pro modální okna, přepínače nastavení, počítadla, vybrané položky seznamu. Pokud je hodnota používána pouze v jednom zobrazení a jeho vnořených komponentách (prostřednictvím @Binding), @State je správná volba. Pro stavy, které by měly přežít zavření zobrazení (např. data formuláře), je @State také vhodný, dokud zobrazení zůstává v hierarchii.
Nepoužívejte @State pro globální stavy aplikace, ukládání síťových dat do mezipaměti nebo objektů používaných na více obrazovkách. Pro tyto účely slouží @StateObject a @EnvironmentObject. @State také není vhodný pro ukládání velkého množství dat — při každé změně bude celé zobrazení překresleno.
@Binding je most mezi @State v nadřazeném zobrazení a podřízeným zobrazením, které potřebuje tento stav měnit. Rodič deklaruje @State a dětská komponenta obdrží Binding prostřednictvím projekce $. Změna Binding v podřízeném zobrazení automaticky aktualizuje @State v rodiči — a naopak. To zajišťuje jednosměrný tok dat s možností zpětné vazby.
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)
}
}
Ve výpisu ParentView vlastní @State text a ChildView obdrží $text jako Binding. TextField uvnitř ChildView se váže k tomuto Binding prostřednictvím text: $text. Když uživatel píše v TextField, hodnota se změní v ChildView přes Binding, což způsobí aktualizaci @State v ParentView. Obě zobrazení se překreslí s novou hodnotou.
Nejčastější chyba — přiřazení třídy vlastnosti @State. Pokud napíšete @State var model = MyClass(), SwiftUI nebude schopen sledovat změny vlastností uvnitř třídy — pouze nahrazení samotného objektu. Pro třídy vždy používejte @StateObject. Druhý běžný problém — deklarování @State bez modifikátoru private, což porušuje princip zapouzdření stavu.
Přímé předávání @State podřízenému zobrazení bez $ — další typická chyba. Pokud předáte TextField(text: text) místo TextField(text: $text), dětská komponenta obdrží obyčejný řetězec, nikoli Binding. Změna textu v TextField nebude synchronizována s nadřazeným @State. Vždy používejte projekci $ pro předávání Binding.
Třetí chyba — více vlastností @State pro související data. Pokud několik hodnot logicky tvoří jeden celek (např. pole formuláře), spojte je do jedné struktury s jedním @State. To zjednodušuje předávání stavu podřízeným zobrazením a snižuje počet samostatných spouštěčů aktualizace.
@State se používá ve většině projektů SwiftUI pro základní interaktivitu. Podívejme se na příklad přihlašovacího formuláře, kde @State spravuje textová pole a stav načítání. Tento vzor se vyskytuje v každé aplikaci — od jednoduchých poznámek po složitá podniková řešení.
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("Přihlásit") {
login()
}.disabled(isLoading)
}
}
private func login() {
isLoading = true
// Provedení síťového požadavku
}
}
V příkladu jsou čtyři vlastnosti @State: email a password pro pole formuláře, isLoading pro indikaci načítání a errorMessage pro zobrazování chyb. Každá vlastnost nezávisle spravuje svou část rozhraní. Při změně isLoading se tlačítko automaticky zablokuje pomocí disabled(isLoading) — bez ruční aktualizace UI.
Často kladené otázky
@State je určen pro lokální stav konkrétního zobrazení. Modifikátor private zaručuje, že jiné komponenty jej nemohou přímo měnit, čímž by porušily zapouzdření. Pro externí přístup použijte projekci $.
Ano, @State podporuje pole a slovníky, protože se jedná o hodnotové typy. Při změně prvku pole však SwiftUI překreslí celé zobrazení. Pro velké seznamy je efektivnější použít @StateObject s @Published.
@State správně pracuje s typy Optional. Při přiřazení nil SwiftUI detekuje změnu a překreslí zobrazení. To je užitečné pro stavy jako errorMessage: String?, kde nil znamená nepřítomnost chyby.
@State uchovává hodnotu, dokud zobrazení zůstává v hierarchii. Pokud je zobrazení z hierarchie odstraněno a znovu přidáno, @State se inicializuje znovu s výchozí hodnotou. Pro perzistenci použijte @AppStorage.
Ano, obalte změnu do withAnimation: withAnimation(.easeInOut) { isExpanded.toggle() }. SwiftUI animuje přechod mezi starým a novým stavem rozhraní s uvedeným typem animace.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také