@State är en Property Wrapper i SwiftUI för att hantera lokalt tillstånd inom en enda vy. SwiftUI ritar automatiskt om vyn vid varje ändring av @State-egenskapen, vilket gör gränssnittet reaktivt utan manella uppdateringsanrop. Enligt Apple Developer Documentation (2025) rekommenderas @State för enkla typer och strukturer som tillhör en enda vy. @State är det enklaste sättet att lägga till interaktivitet i ett SwiftUI-gränssnitt.
Huvudpunkter
@State är en inbyggd Property Wrapper i SwiftUI som låter en vy lagra och övervaka sitt eget tillstånd. När värdet på @State ändras ritar SwiftUI automatiskt om vyn genom att anropa body-egenskapen igen. Detta är grunden för reaktiv programmering i SwiftUI: utvecklaren deklarerar tillståndet och ramverket tar hand om synkroniseringen av gränssnittet.
@State skapar ett lagringsområde på högen som hanteras av SwiftUI. Detta område är beständigt — det överlever upprepade initieringar av vystrukturen som sker vid varje rendering. SwiftUI använder vyidentifieraren (genererad baserat på position i hierarkin) för att binda @State-egenskapen till en specifik vy. Tack vare detta återställs inte tillståndet när den överordnade vyn uppdateras.
En viktig begränsning: @State är endast avsett för värdetyper (strukturer, uppräkningar, primitiver). För referenstyper (klasser) använd @StateObject eller @ObservedObject. Om du tilldelar en klass till en @State-egenskap kan SwiftUI inte upptäcka ändringar inuti objektet — endast ersättning av hela referensen.
SwiftUI implementerar @State genom den interna Storage-mekanismen. Varje @State-egenskap får en dedikerad minnescell som lagras i vyens speciella lagringscontainer. När en skrivning till wrappedValue sker, meddelar SwiftUI via didSet sin beroendegraf (dependency graph) om behovet av omritning.
struct ContentView: View {
@State private var name: String = "User"
@State private var isLoggedIn: Bool = false
var body: some View {
VStack {
Text("Hej, \(name)")
Button(isLoggedIn ? "Logga ut" : "Logga in") {
isLoggedIn.toggle()
}
}
}
}
I exemplet finns två @State-egenskaper: name (String) och isLoggedIn (Bool). Vid anrop av isLoggedIn.toggle() markerar SwiftUI ContentView som uppdateringsbehövande och startar om body i nästa renderingscykel. Nyckelpunkten: @State-egenskaper deklareras alltid med private-modifieraren — detta är en signal om att tillståndet uteslutande tillhör den aktuella vyn och inte bör ändras utifrån direkt.
För att observera ändringar använder SwiftUI CurrentValueSubject från Combine. Varje @State-egenskap skapar en dold utgivare som meddelar systemet vid varje ändring. Detta gör att SwiftUI bara kan rita om den minimalt nödvändiga uppsättningen vyer, vilket undviker fullständig uppdatering av hierarkin.
@State är optimal för enkla lokala tillstånd: textfält för sökning, booleska flaggor för modala fönster, inställningsomkopplare, räknare, valda listelement. Om värdet endast används i en vy och dess kapslade komponenter (via @Binding), är @State rätt val. För tillstånd som bör överleva stängning av vyn (t.ex. formulärdata) är @State också lämpligt så länge vyn förblir i hierarkin.
Använd inte @State för globala applikationstillstånd, cachelagring av nätverksdata eller objekt som används på flera skärmar. För dessa ändamål är @StateObject och @EnvironmentObject avsedda. @State är inte heller lämpligt för lagring av stora datamängder — varje gång det ändras kommer hela vyn att ritas om.
@Binding är en bro mellan @State i den överordnade vyn och den underordnade vyn som behöver ändra detta tillstånd. Föräldern deklarerar @State och den underordnade komponenten får Binding via $-projektionen. Ändring av Binding i den underordnade vyn uppdaterar automatiskt @State i föräldern — och vice versa. Detta säkerställer ett enkelriktat dataflöde med möjlighet till återkoppling.
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)
}
}
I listningen har ParentView @State text, och ChildView får $text som Binding. TextField inuti ChildView binder till detta Binding via text: $text. När användaren skriver i TextField ändras värdet i ChildView via Binding, vilket orsakar uppdatering av @State i ParentView. Båda vyerna ritas om med det nya värdet.
Det vanligaste misstaget — tilldelning av en klass till en @State-egenskap. Om du skriver @State var model = MyClass() kan SwiftUI inte spåra ändringar av egenskaper inuti klassen — endast ersättning av själva objektet. För klasser använd alltid @StateObject. Det andra vanliga problemet — deklarering av @State utan private-modifieraren, vilket bryter mot principen om tillståndsinkapsling.
Direkt överföring av @State till en underordnad vy utan $ — ytterligare ett typiskt misstag. Om du skickar TextField(text: text) istället för TextField(text: $text) får den underordnade komponenten en vanlig sträng, inte ett Binding. Ändring av text i TextField kommer inte att synkroniseras med det överordnade @State. Använd alltid $-projektionen för att överföra Binding.
Det tredje misstaget — flera @State-egenskaper för relaterad data. Om flera värden logiskt utgör en helhet (t.ex. formulärfält), kombinera dem i en struktur med ett enda @State. Detta förenklar överföring av tillstånd till underordnade vyer och minskar antalet separata uppdateringsutlösare.
@State används i de flesta SwiftUI-projekt för grundläggande interaktivitet. Låt oss titta på ett exempel på ett inloggningsformulär, där @State hanterar textfält och laddningstillstånd. Detta mönster finns i varje applikation — från enkla anteckningar till komplexa företagslösningar.
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("Logga in") {
login()
}.disabled(isLoading)
}
}
private func login() {
isLoading = true
// Utför nätverksbegäran
}
}
I exemplet finns fyra @State-egenskaper: email och password för formulärfält, isLoading för laddningsindikering och errorMessage för att visa fel. Varje egenskap hanterar självständigt sin del av gränssnittet. När isLoading ändras blockeras knappen automatiskt via disabled(isLoading) — utan manuell UI-uppdatering.
Vanliga frågor
@State är avsett för lokalt tillstånd för en specifik vy. Private-modifieraren garanterar att andra komponenter inte kan ändra det direkt, vilket skulle bryta inkapslingen. För extern åtkomst använd $-projektionen.
Ja, @State stöder arrayer och ordböcker eftersom de är värdetyper. Men när ett arrayelement ändras ritar SwiftUI om hela vyn. För stora listor är det effektivare att använda @StateObject med @Published.
@State fungerar korrekt med Optional-typer. Vid tilldelning av nil upptäcker SwiftUI ändringen och ritar om vyn. Detta är praktiskt för tillstånd som errorMessage: String?, där nil innebär frånvaro av fel.
@State behåller värdet så länge vyn förblir i hierarkin. Om vyn tas bort från hierarkin och läggs till igen initieras @State på nytt med standardvärdet. För beständighet använd @AppStorage.
Ja, omge ändringen med withAnimation: withAnimation(.easeInOut) { isExpanded.toggle() }. SwiftUI animerar övergången mellan det gamla och nya tillståndet i gränssnittet med den angivna animationstypen.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också