@StateObject ist ein Property Wrapper in SwiftUI, der eine ObservableObject-Instanz während des gesamten Lebenszyklus einer View erstellt und besitzt. Wenn eine View zum ersten Mal auf dem Bildschirm erscheint, initialisiert @StateObject das Objekt und speichert es, bis die View aus dem Speicher entfernt wird. Dies stellt sicher, dass Daten beim Neuaufbau der Oberfläche nicht zurückgesetzt werden — zum Beispiel beim Wechseln des Designs oder beim Aktualisieren der übergeordneten View. Laut Apple Developer Documentation (2025) sollte @StateObject als primäre Quelle der Wahrheit (Source of Truth) für ObservableObject in der SwiftUI-Hierarchie verwendet werden, während untergeordnete Views das bereits erstellte Objekt über @ObservedObject oder @EnvironmentObject erhalten.
Wichtige Punkte
@StateObject ist ein Property Wrapper, der in iOS 14 eingeführt wurde und es einer View ermöglicht, eine Instanz einer Klasse zu erstellen und zu besitzen, die dem ObservableObject-Protokoll entspricht. Im Gegensatz zu @State, das mit Wertetypen (Structs) arbeitet, ist @StateObject für Referenztypen konzipiert — Klassen, die SwiftUI über Änderungen ihrer Eigenschaften benachrichtigen können.
Wenn eine View @StateObject var viewModel: MyViewModel verwendet, erstellt SwiftUI automatisch eine Instanz von MyViewModel, wenn die View zum ersten Mal angezeigt wird, und speichert sie in einem speziellen Framework-Speicher. Bei jeder Aktualisierung der View (z. B. wenn sich der Elternstatus ändert) erstellt SwiftUI das Objekt nicht neu — es verwendet die vorhandene Instanz, bis die View aus der Hierarchie entfernt wird.
Laut Apple WWDC Session 10137 (2024) löst @StateObject das Datenverlustproblem, das in iOS 13 beim Neuerstellen von Views bestand, bei dem Entwickler gezwungen waren, ObservableObject in der übergeordneten View zu erstellen und über den Initialisierer zu übergeben. Dies führte zu Code-Duplizierung und dem Risiko einer versehentlichen Neuerstellung des Objekts.
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("Count: \(viewModel.count)")
Button("Increment", action: viewModel.increment)
}
}
}
Der Mechanismus von @StateObject basiert auf der Integration von SwiftUI mit dem Combine-Framework. Wenn ein ObservableObject seine Eigenschaften mit dem @Published-Attribut markiert, abonniert SwiftUI automatisch Änderungen über den in das ObservableObject-Protokoll integrierten Publisher. Wenn sich eine veröffentlichte Eigenschaft ändert, sendet das Objekt ein Signal über den objectWillChange-Publisher, was eine Neuzeichnung aller Views auslöst, die dieses Objekt beobachten.
SwiftUI speichert die ObservableObject-Instanz in einem speziellen Speicher, der an eine bestimmte View-Instanz gebunden ist. Dieser Speicher wird beim ersten Rendern einmal erstellt und existiert, bis die View zerstört wird. Aus diesem Grund garantiert @StateObject Referenzstabilität — SwiftUI verwaltet den Speicher automatisch, ohne auf den Initialisierer der View angewiesen zu sein.
Laut objc.io — Thinking in SwiftUI (2025) verwendet die interne Implementierung von @StateObject einen ähnlichen Mechanismus wie @State, jedoch für Referenztypen: SwiftUI erstellt einen Boxing-Wrapper um das Objekt und verwaltet seinen Lebenszyklus über einen eigenen Allokator, der für häufige Neuaufbauten der View-Hierarchie optimiert ist.
Der Hauptunterschied zwischen @StateObject und @ObservedObject liegt darin, wer das Objekt besitzt. @StateObject erstellt und speichert das Objekt — es ist der Eigentümer. @ObservedObject beobachtet nur das Objekt, das an anderer Stelle erstellt und über den Initialisierer oder eine Eigenschaft übergeben wurde.
| Merkmal | @StateObject | @ObservedObject |
|---|---|---|
| Besitz | Erstellt und besitzt das Objekt | Beobachtet nur |
| Initialisierung | Innerhalb der View über init/Standard | Extern, über Parameter übergeben |
| Lebenszyklus | An den Lebenszyklus der View gebunden | Nicht von der View gesteuert |
| Neuerstellung | Wird bei Aktualisierung nicht neu erstellt | Kann extern ersetzt werden |
| iOS-Version | iOS 14+ | iOS 13+ |
Die Regel ist einfach: Wenn die View das ObservableObject erstellt — verwende @StateObject. Wenn die View nur ein bereits erstelltes Objekt vom Elternteil erhält — verwende @ObservedObject. Ein Verstoß gegen diese Regel führt entweder zu Datenverlust (bei Verwendung von @ObservedObject für den Besitz) oder zu übermäßiger Objekterstellung (bei Verwendung von @StateObject für die Beobachtung).
@StateObject sollte in Views verwendet werden, die die Quelle der Wahrheit für einen bestimmten Datensatz sind. Typische Szenarien umfassen Bildschirme mit eigenem View Model, Root-Bildschirme von Navigationsstapeln und modale Präsentationen, die ihren eigenen Zustand verwalten.
struct ProfileView: View {
@StateObject var viewModel = ProfileViewModel()
var body: some View {
NavigationStack {
Form {
TextField("Name", text: $viewModel.name)
TextField("Email", text: $viewModel.email)
Button("Save") {
viewModel.saveProfile()
}
}
.navigationTitle("Profile")
}
}
}
Die Initialisierung von @StateObject mit Parametern erfordert eine spezielle Syntax, da SwiftUI die Objekterstellung selbst verwaltet. Sie können nicht einfach Parameter an den Initialisierer übergeben — Sie müssen einen Escape-Closure oder eine separate Factory-Methode verwenden.
Laut Swift by Sundell (2024) ist der sauberste Ansatz die Verwendung einer Factory-Methode oder eines Closures, das SwiftUI beim ersten Erstellen des Objekts aufruft. Ein alternativer Ansatz besteht darin, das ObservableObject in der übergeordneten View zu initialisieren und es über @StateObject mit dem Standard-Initialisierer zu übergeben.
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)
}
}
Es ist wichtig zu beachten, dass der View-Initialisierer mit @StateObject einen Unterstrich vor dem Eigenschaftsnamen (_viewModel) verwenden sollte, um auf den Property Wrapper selbst zuzugreifen, nicht auf seinen Wert. Dies ist ein standardmäßiges Swift-Muster für die Arbeit mit Property Wrappern in Initialisierern.
Der häufigste Fehler ist die Verwendung von @ObservedObject anstelle von @StateObject für eine View, die das Objekt besitzen sollte. In diesem Fall wird das Objekt bei jeder Neuerstellung des Elternteils neu erstellt, was zum Verlust aller angesammelten Daten führt. Dieser Fehler ist besonders tückisch in komplexen Hierarchien mit NavigationStack oder TabView.
Um diese Probleme zu vermeiden, befolgen Sie eine einfache Regel: ein @StateObject pro Quelle der Wahrheit. Wenn Daten über mehrere Bildschirme hinweg gemeinsam genutzt werden sollen — erstellen Sie @StateObject einmal in der Root-View und übergeben Sie es über @ObservedObject oder @EnvironmentObject an untergeordnete Elemente.
// ❌ Wrong: @ObservedObject for owning an object
struct BadView: View {
@ObservedObject var vm = ViewModel() // will be recreated on each update!
}
// ✅ Correct: @StateObject for owning
struct GoodView: View {
@StateObject var vm = ViewModel() // created once for View lifetime
}
Häufig gestellte Fragen
@State arbeitet mit Wertetypen (Structs, Zeichenketten, Zahlen) und speichert den Wert direkt im SwiftUI-Speicher. @StateObject arbeitet mit Referenztypen — Klassen, die ObservableObject entsprechen. @State eignet sich für einfache lokale Zustände, @StateObject für komplexe Objekte mit Logik und veröffentlichten Eigenschaften.
Nein, @StateObject ist erst ab iOS 14 verfügbar. Für iOS 13 verwenden Sie @ObservedObject und erstellen das ObservableObject in der übergeordneten View über @State mit manuellem Lebenszyklus-Management. Eine Alternative ist die Verwendung von @State mit einem Struct anstelle einer Klasse für Daten, die keine Referenzsemantik erfordern.
Die untergeordnete View erstellt ihre eigene Kopie des ObservableObject, völlig unabhängig von der des Elternteils. Änderungen in einer wirken sich nicht auf die andere aus. Dies ist fast immer ein Fehler: Verwenden Sie @ObservedObject, um ein Objekt vom Elternteil zu erhalten, und @StateObject nur, um ein neues Objekt innerhalb der View zu erstellen.
Das Objekt wird zerstört, wenn die View, die es erstellt hat, vollständig aus der SwiftUI-Hierarchie entfernt wird. Für einen Bildschirm im NavigationStack geschieht dies beim Pop vom Navigationsstapel. Für ein modales Fenster — beim Schließen. Für TabView — beim Wechseln des Tabs, wenn die View nicht zwischengespeichert wird.
Verwenden Sie einen benutzerdefinierten init mit Zugriff auf den Property Wrapper über Unterstrich: _viewModel = StateObject(wrappedValue: MyViewModel(param: value)). Dieses Muster ermöglicht es, beliebige Parameter an das ObservableObject zu übergeben, während die Garantie der einmaligen Objekterstellung während der Lebensdauer der View erhalten bleibt.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch