@StateObject: Was es ist, Unterschied zu @ObservedObject und Beispiele

Autor: IT Sectr Veröffentlicht: 2026-06-19 Lesezeit: 7 Min.

@StateObject ist ein Property Wrapper in SwiftUI zum Erstellen und Besitzen einer ObservableObject-Instanz direkt in einer View. SwiftUI garantiert, dass das Objekt einmal pro Lebenszyklus der Ansicht initialisiert und bei erneuten Renderings nicht neu erstellt wird. Laut der Apple Developer Documentation (2025) wird @StateObject für Root-Views empfohlen, die eine Datenquelle erstellen. @StateObject ist die richtige Wahl zum Besitzen eines ObservableObject in der SwiftUI-Hierarchie.

Wichtige Punkte

  • @StateObject — Property Wrapper zum Erstellen und Besitzen von ObservableObject in einer View
  • Einzelne Instanz — das Objekt wird einmal erstellt und bei Renderings nicht neu erstellt
  • Quelle der Wahrheit — @StateObject garantiert Datenstabilität für die gesamte Hierarchie
  • Unterschied zu @ObservedObject — @ObservedObject besitzt das Objekt nicht und kann es verlieren
  • Root-Views — @StateObject wird in der View verwendet, die das Objekt erstellt

Was ist @StateObject in SwiftUI?

@StateObject ist ein Property Wrapper, der in SwiftUI 2.0 (iOS 14) eingeführt wurde und die Fähigkeiten von @ObservedObject und @State kombiniert. Wie @ObservedObject abonniert es Änderungen an ObservableObject. Wie @State garantiert es, dass Daten wiederholte Initialisierungen der View-Struktur überleben. @StateObject erstellt das Objekt einmal, wenn die View zum ersten Mal auf dem Bildschirm erscheint, und speichert es im SwiftUI-Heap.

Vor @StateObject verwendeten Entwickler @ObservedObject für alle ObservableObjects, einschließlich der in Views erstellten. Dies führte zu häufigem Datenverlust, wenn die Eltern-View aktualisiert wurde, wodurch die View-Struktur neu erstellt und die @ObservedObject-Instanz mitgenommen wurde. @StateObject löste dies durch die Hinzufügung einer Stabilitätsgarantie.

Die Hauptregel: @StateObject wird in der View verwendet, die das Objekt im Standard-Initialisierer (let model = ViewModel()) erstellt. Kind-Views, die dieses Objekt erhalten, verwenden @ObservedObject. Diese Trennung garantiert eine einzige Quelle der Wahrheit in der gesamten Hierarchie.

Lebenszyklus von @StateObject

SwiftUI verwaltet den Lebenszyklus von @StateObject über einen Storage-Manager, der @State ähnelt. Wenn die View zum ersten Mal erscheint, weist SwiftUI Speicher für das Objekt zu und speichert es in einem persistenten Bereich. Bei nachfolgenden Renderings (Body-Aufrufen) wird das Objekt nicht neu erstellt—die vorhandene Instanz wird verwendet. Das Objekt lebt, solange die View in der Hierarchie ist.

Wenn die View aus der Hierarchie entfernt wird, zerstört SwiftUI das @StateObject und ruft deinit auf. Wenn die View wieder zur Hierarchie hinzugefügt wird, wird eine neue Instanz erstellt. Dies ist beim Design wichtig zu beachten: Wenn Sie Daten zwischen View-Entfernungen bewahren müssen, verwenden Sie eine Service-Schicht (Singleton oder DI) oder @AppStorage für Persistenz.

swift
class TimerViewModel: ObservableObject {
    @Published var seconds: Int = 0
    private var timer: Timer?

    func start() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            self.seconds += 1
        }
    }

    deinit {
        timer?.invalidate()
    }
}

struct TimerView: View {
    @StateObject var viewModel = TimerViewModel()

    var body: some View {
        Text("\(viewModel.seconds)s")
            .onAppear { viewModel.start() }
    }
}

Im Beispiel wird TimerViewModel über @StateObject erstellt und lebt, solange TimerView auf dem Bildschirm ist. Der Timer startet in onAppear und stoppt in deinit. Wenn @ObservedObject verwendet würde, würde jedes Rendern von TimerView einen neuen TimerViewModel mit Sekunden = 0 erstellen, und der Timer würde niemals korrekt funktionieren. @StateObject garantiert, dass das viewModel eindeutig und stabil ist.

@StateObject vs @ObservedObject: Vergleich

Die Wahl zwischen @StateObject und @ObservedObject hängt davon ab, wer das Objekt besitzt. Wenn die View das Objekt erstellt—@StateObject. Wenn die View ein fertiges Objekt erhält—@ObservedObject. Diese Regel ist so wichtig, dass Xcode eine Warnung ausgibt, wenn @StateObject in einer Kind-View verwendet wird, die das Objekt über einen Initialisierer erhält.

SituationEmpfohlener Wrapper
View erstellt Modell über ViewModel()@StateObject
View erhält Modell vom Eltern-Element@ObservedObject
Modell wird in einer View verwendet@StateObject
Modell wird über Environment übergeben@EnvironmentObject
Modell wird für Vorschauen benötigt@ObservedObject + Mock

In der Praxis wird @StateObject zu Beginn eines Projekts oft in der Root-View und @ObservedObject in allen Kind-Views verwendet. Mit dem Wachstum der Anwendung können einige @StateObject-Instanzen durch @EnvironmentObject ersetzt werden, um die Hierarchie zu vereinfachen. @StateObject bleibt jedoch die beste Wahl für modulare Bildschirme mit eigener Logik.

Verwendungsmuster von @StateObject

Das erste Muster—MVVM mit @StateObject. ViewModel als ObservableObject wird in der View über @StateObject erstellt. ViewModel enthält @Published-Eigenschaften und Geschäftslogik. Die View abonniert Änderungen und aktualisiert die Oberfläche. Dieser Ansatz bietet testbare Isolation: ViewModel kann ohne UI getestet werden, indem eine Instanz direkt erstellt wird.

Das zweite Muster—@StateObject mit Abhängigkeiten. Wenn ViewModel Dienste benötigt, verwenden Sie die Initialisierung mit Parametern. Zum Beispiel @StateObject var viewModel = UserViewModel(api: APIClient.shared). Seien Sie jedoch vorsichtig: Parameter werden bei jedem Body-Rendering berechnet, aber das Objekt wird nur einmal erstellt. SwiftUI ignoriert nachfolgende @StateObject-Initialisierungen.

Das dritte Muster—verschachtelte @StateObjects. In SwiftUI können mehrere @StateObjects in einer View vorhanden sein, aber das ist selten gerechtfertigt. Normalerweise verwaltet ein @StateObject den gesamten Datensatz der View. Wenn die Logik zu komplex wird, teilen Sie sie in eine Komposition von @ObservedObject-Diensten innerhalb eines @StateObject auf.

swift
struct AppView: View {
    @StateObject var router = NavigationRouter()
    @StateObject var auth = AuthViewModel()

    var body: some View {
        ContentView()
            .environmentObject(router)
            .environmentObject(auth)
    }
}

Im Beispiel erstellt AppView zwei @StateObjects: NavigationRouter zur Verwaltung der Navigation und AuthViewModel für die Authentifizierung. Beide Objekte werden über environmentObject in die Environment injiziert. Jede Kind-View kann über @EnvironmentObject auf sie zugreifen, ohne die Initialisiererkette zu durchlaufen.

@StateObject und Initialisierung mit Parametern

@StateObject unterstützt die Initialisierung mit beliebigen Parametern, jedoch mit einem wichtigen Vorbehalt: Der Initialisierer wird nur einmal aufgerufen. Bei nachfolgenden Body-Renderings werden neue Parameterwerte ignoriert. Das bedeutet, wenn Sie @State var id: Int = 5 an @StateObject var vm = ViewModel(id: id) übergeben, erhält ViewModel bei Änderung von id den neuen Wert nicht.

Verwenden Sie zur Lösung dieses Problems onReceive oder onAppear zur Synchronisation. Abonnieren Sie Parameteränderungen innerhalb des ViewModel über Combine oder übergeben Sie Parameter über die .onChange(of:)-Methode auf View-Ebene. Eine Alternative ist die Verwendung von @ObservedObject anstelle von @StateObject, wenn das Objekt dynamisch auf externe Änderungen reagieren soll.

swift
struct DetailView: View {
    let itemId: Int
    @StateObject var viewModel = DetailViewModel()

    var body: some View {
        Text(viewModel.title)
            .onAppear { viewModel.load(id: itemId) }
    }
}

Der richtige Ansatz: DetailView erhält itemId als let-Eigenschaft (über den Initialisierer der Struktur übergeben), und @StateObject erstellt DetailViewModel ohne Parameter. In onAppear wird die Methode load(id:) aufgerufen, um Daten für die übergebene ID zu laden. Dies garantiert, dass das ViewModel durch den @StateObject-Mechanismus erstellt wird, aber die Daten bei jedem Erscheinen der View mit der aktuellen ID geladen werden.

Häufige Fehler mit @StateObject

Der Hauptfehler—die Verwendung von @StateObject in Kind-Views, die das Objekt von einem Eltern-Element erhalten. Wenn ParentView @StateObject model erstellt und ChildView @StateObject var model: ModelType (mit einem Standardparameter) deklariert, erstellt ChildView eine eigene unabhängige Instanz. Die Eltern- und Kind-Objekte sind nicht verbunden, und Änderungen in einem wirken sich nicht auf das andere aus.

Der zweite Fehler—Platzieren von @StateObject in List oder ForEach. Jedes Listenelement erstellt sein eigenes @StateObject, was zu mehreren unabhängigen Instanzen führt. Für Listen ist der richtige Ansatz, ein einzelnes ObservableObject über @ObservedObject an alle Elemente zu übergeben oder Identifiable-Strukturen mit @State innerhalb von List zu verwenden.

Das dritte Problem—fehlende Bereinigung in deinit. @StateObject lebt für den gesamten View-Lebenszyklus. Wenn das Objekt Timer, Combine-Abonnements oder Netzwerkanfragen erstellt, muss deinit diese abbrechen. Andernfalls sind Speicherlecks und fortgesetzte Hintergrundarbeit nach dem Schließen des Bildschirms unvermeidlich. Verwenden Sie immer einen Combine Cancellable-Speicher oder invalidieren Sie Timer in deinit.

Häufig gestellte Fragen

Wann wurde @StateObject in SwiftUI eingeführt?

@StateObject wurde in SwiftUI 2.0 auf der WWDC 2020 zusammen mit iOS 14, macOS 11, watchOS 7 und tvOS 14 hinzugefügt. Davor war @ObservedObject die einzige Möglichkeit, mit ObservableObject zu arbeiten, was häufig zu Datenverlustfehlern führte.

Kann @StateObject optional sein?

Nein, @StateObject unterstützt keine Optional-Typen. Das Objekt muss bei der Deklaration initialisiert werden. Wenn Sie ein optionales Objekt benötigen, verwenden Sie @ObservedObject oder @EnvironmentObject mit einem optionalen Typ.

Wie überprüft man, dass @StateObject nur einmal erstellt wird?

Fügen Sie print(#function) zum Initialisierer und deinit des ObservableObject hinzu. Wenn init bei Renderings nicht aufgerufen wird—funktioniert @StateObject korrekt. Wenn init jedes Mal aufgerufen wird—ersetzen Sie @ObservedObject durch @StateObject.

Kann @StateObject mit UIKit über UIHostingController verwendet werden?

Ja, @StateObject funktioniert in SwiftUI-Views, die über UIHostingController in UIKit eingebettet sind. Der Objektlebenszyklus ist an die SwiftUI-View gebunden, nicht an den UIViewController. Wenn die SwiftUI-View ersetzt wird, wird das @StateObject zerstört.

Was ist besser: ein @StateObject mit großem ViewModel oder mehrere kleine?

Mehrere kleine @StateObjects mit getrennten Verantwortlichkeiten. Dies verbessert Testbarkeit, Wiederverwendbarkeit und Leistung—wenn sich ein Objekt ändert, werden nur die abonnierten Teile der Oberfläche neu gezeichnet, nicht die gesamte View.

Zusammenfassung

  • @StateObject — Property Wrapper zum Erstellen und Besitzen von ObservableObject in einer View
  • Einzelne Instanz — das Objekt wird bei nachfolgenden Body-Renderings nicht neu erstellt
  • Quelle der Wahrheit — @StateObject in der Root-View garantiert Datenstabilität für die Hierarchie
  • Auswahlregel — @StateObject zum Erstellen, @ObservedObject zum Erhalten eines fertigen Objekts
  • Initialisierung — Parameter in @StateObject werden einmal berechnet, Updates werden nicht verfolgt
  • Deinit — obligatorische Bereinigung von Timern und Abonnements im deinit des ObservableObject
  • iOS 14+ — @StateObject ist verfügbar ab iOS 14, macOS 11, watchOS 7, tvOS 14

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.

Projekt besprechen

Lesen Sie auch