@StateObject är en property wrapper i SwiftUI som skapar och äger en ObservableObject-instans under hela Viewns livscykel. När View först visas på skärmen initierar @StateObject objektet och lagrar det tills View tas bort från minnet. Detta garanterar att data inte återställs vid ombyggnad av gränssnittet — till exempel vid temabytest eller uppdatering av förälder-View. Enligt Apple Developer Documentation (2025) bör @StateObject användas som den främsta sanningskällan (source of truth) för ObservableObject i SwiftUI-hierarkin, medan underordnade View får det redan skapade objektet via @ObservedObject eller @EnvironmentObject.
Huvudpunkter
@StateObject är en property wrapper som introducerades i iOS 14 och som gör det möjligt för ett View att skapa och äga en instans av en klass som följer ObservableObject-protokollet. Till skillnad från @State som arbetar med värdetyper (strukturer), är @StateObject avsett för referenstyper — klasser som kan meddela SwiftUI om ändringar i sina egenskaper.
När ett View använder @StateObject var viewModel: MyViewModel, skapar SwiftUI automatiskt en MyViewModel-instans vid första visningen av View och lagrar den i frameworkets särskilda lagring. Vid varje uppdatering av View (till exempel vid ändring av förälderns tillstånd) återskapar SwiftUI inte objektet — det använder den befintliga instansen tills View tas bort från hierarkin.
Enligt Apple WWDC Session 10137 (2024) löser @StateObject problemet med dataförlust vid ombyggnad av View som fanns i iOS 13, när utvecklare var tvungna att skapa ObservableObject i förälder-View och skicka det via initieraren. Detta ledde till kodduplicering och risk för oavsiktlig återskapning av objektet.
import SwiftUI
class CounterViewModel: ObservableObject {
@Published var count: Int = 0
func increment() {
count += 1
}
}
struct CounterView: View {
@StateObject var viewModel = CounterViewModel()
var body: some View {
VStack {
Text("Antal: \(viewModel.count)")
Button("Öka", action: viewModel.increment)
}
}
}
Mekanismen för @StateObject är baserad på integrationen av SwiftUI med Combine-frameworket. När ObservableObject markerar sina egenskaper med attributet @Published, prenumererar SwiftUI automatiskt på ändringar via den inbyggda publishern i ObservableObject-protokollet. När en publicerad egenskap ändras skickar objektet en signal via objectWillChange-publishern, vilket utlöser omritning av alla View som observerar detta objekt.
SwiftUI lagrar ObservableObject-instansen i en särskild lagring som är bunden till en specifik View-instans. Denna lagring skapas en gång vid första rendereringen och finns kvar tills View förstörs. Det är därför @StateObject garanterar stabiliteten för referensen till objektet — SwiftUI hanterar minnet automatiskt, utan att förlita sig på Viewns initierare.
Enligt objc.io — Thinking in SwiftUI (2025) använder den interna implementeringen av @StateObject en mekanism som liknar @State, men för referenstyper: SwiftUI skapar ett boxing-omslag runt objektet och hanterar dess livscykel via en egen allokerare, optimerad för frekventa ombyggnationer av View-hierarkin.
Huvudskillnaden mellan @StateObject och @ObservedObject är vem som äger objektet. @StateObject skapar och lagrar objektet — det är ägaren. @ObservedObject observerar bara ett objekt som har skapats någon annanstans och skickats via initieraren eller en egenskap.
| Egenskap | @StateObject | @ObservedObject |
|---|---|---|
| Ägande | Skapar och äger objektet | Observerar bara |
| Initiering | Inuti View via init/default | Utifrån, skickas via parameter |
| Livscykel | Bunden till Viewns livscykel | Kontrolleras inte av View |
| Återskapande | Återskapas inte vid uppdatering | Kan ersättas utifrån |
| iOS-version | iOS 14+ | iOS 13+ |
Regeln är enkel: om View skapar ObservableObject — använd @StateObject. Om View bara tar emot ett redan färdigt objekt från föräldern — använd @ObservedObject. Brott mot denna regel leder antingen till dataförlust (om du använder @ObservedObject för ägande) eller till överdriven objektsskapande (om du använder @StateObject för observation).
@StateObject bör användas i de View som är sanningskällan för en specifik datamängd. Typiska scenarier inkluderar skärmar med egen view model, rot-skärmar i navigationsstackar och modala presentationer som hanterar eget tillstånd.
struct ProfileView: View {
@StateObject var viewModel = ProfileViewModel()
var body: some View {
NavigationStack {
Form {
TextField("Name", text: $viewModel.name)
TextField("Email", text: $viewModel.email)
Button("Spara") {
viewModel.saveProfile()
}
}
.navigationTitle("Profile")
}
}
}
Initiering av @StateObject med parametrar kräver speciell syntax eftersom SwiftUI hanterar skapandet av objektet oberoende. Man kan inte bara skicka parametrar till initieraren — man måste använda en escaping closure eller en separat skapandemetod.
Enligt Swift by Sundell (2024) är den renaste metoden att använda en fabriksmetod eller en closure som SwiftUI anropar vid första skapandet av objektet. Ett alternativt tillvägagångssätt — initiera ObservableObject i förälder-View och skicka det via @StateObject med standardinitieraren.
class UserViewModel: ObservableObject {
@Published var user: User
init(user: User) {
self.user = user
}
}
struct UserDetailView: View {
@StateObject var viewModel: UserViewModel
init(user: User) {
_viewModel = StateObject(wrappedValue: UserViewModel(user: user))
}
var body: some View {
Text(viewModel.user.name)
}
}
Det är viktigt att komma ihåg att View-initieraren med @StateObject måste använda understreck före egenskapsnamnet (_viewModel) för att komma åt själva property wrappern, inte dess värde. Detta är ett standard Swift-mönster för att arbeta med property wrappers i initierare.
Det vanligaste misstaget är att använda @ObservedObject istället för @StateObject för ett View som borde äga objektet. I detta fall kommer objektet att återskapas vid varje ombyggnad av föräldern, vilket leder till förlust av all ackumulerad data. Detta misstag är särskilt lömskt i komplexa hierarkier med NavigationStack eller TabView.
För att undvika dessa problem, följ den enkla regeln: en @StateObject per sanningskälla. Om data måste delas mellan flera skärmar — skapa @StateObject en gång i rot-View och skicka det via @ObservedObject eller @EnvironmentObject till underordnade element.
// ❌ Fel: @ObservedObject för att äga ett objekt
struct BadView: View {
@ObservedObject var vm = ViewModel() // kommer att återskapas vid varje uppdatering!
}
// ✅ Rätt: @StateObject för att äga
struct GoodView: View {
@StateObject var vm = ViewModel() // skapades en gång för Viewns livstid
}
Vanliga frågor
@State arbetar med värdetyper (strukturer, strängar, tal) och lagrar värdet direkt i SwiftUI-lagringen. @StateObject arbetar med referenstyper — klasser som följer ObservableObject. @State är lämpligt för enkla lokala tillstånd, @StateObject för komplexa objekt med logik och publicerade egenskaper.
Nej, @StateObject är endast tillgängligt från iOS 14 och uppåt. För iOS 13 använder du @ObservedObject och skapar ObservableObject i förälder-View via @State med manuell livscykelhantering. Ett alternativ är att använda @State med struct istället för class för data som inte kräver referenssemantik.
Det underordnade View kommer att skapa sin egen kopia av ObservableObject, helt oberoende av föräldern. Ändringar i den ena kommer inte att återspeglas i den andra. Detta är nästan alltid ett misstag: använd @ObservedObject för att ta emot objektet från föräldern och @StateObject endast för att skapa ett nytt objekt inuti View.
Objektet förstörs när View som skapade det helt tas bort från SwiftUI-hierarkin. För en skärm i NavigationStack sker detta vid pop från navigationsstacken. För ett modalt fönster — vid stängning. För TabView — vid byte av flik, om View inte cachas.
Använd en anpassad init med åtkomst till property wrappern via understreck: _viewModel = StateObject(wrappedValue: MyViewModel(param: value)). Detta mönster gör det möjligt att skicka alla parametrar till ObservableObject samtidigt som garantin för engångsskapande av objektet under Viewns livstid behålls.
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å