@StateObject je property wrapper ve SwiftUI, který vytváří a vlastní instanci ObservableObject po celou dobu životního cyklu View. Když se View poprvé objeví na obrazovce, @StateObject inicializuje objekt a uchovává jej, dokud není View odstraněno z paměti. To zaručuje, že data nebudou resetována při přestavbě rozhraní — například při změně motivu nebo aktualizaci nadřazeného View. Podle Apple Developer Documentation (2025) by měl být @StateObject používán jako hlavní zdroj pravdy (source of truth) pro ObservableObject v hierarchii SwiftUI, zatímco podřízené View získávají již vytvořený objekt prostřednictvím @ObservedObject nebo @EnvironmentObject.
Hlavní body
@StateObject je property wrapper představený v iOS 14, který umožňuje View vytvářet a vlastnit instanci třídy vyhovující protokolu ObservableObject. Na rozdíl od @State, který pracuje s hodnotovými typy (strukturami), je @StateObject určen pro referenční typy — třídy, které mohou SwiftUI informovat o změnách svých vlastností.
Když View používá @StateObject var viewModel: MyViewModel, SwiftUI automaticky vytvoří instanci MyViewModel při prvním zobrazení View a uloží ji do speciálního úložiště frameworku. Při každé aktualizaci View (například při změně nadřazeného stavu) SwiftUI objekt znovu nevytváří — používá stávající instanci, dokud není View odstraněno z hierarchie.
Podle Apple WWDC Session 10137 (2024) řeší @StateObject problém ztráty dat při přestavbě View, který existoval v iOS 13, kdy vývojáři museli vytvářet ObservableObject v nadřazeném View a předávat jej přes inicializátor. To vedlo k duplikaci kódu a riziku náhodného znovuvytvoření objektu.
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("Počet: \(viewModel.count)")
Button("Zvýšit", action: viewModel.increment)
}
}
}
Mechanismus @StateObject je založen na integraci SwiftUI s frameworkem Combine. Když ObservableObject označí své vlastnosti atributem @Published, SwiftUI se automaticky přihlásí ke změnám prostřednictvím publisheru vestavěného v protokolu ObservableObject. Při změně publikované vlastnosti objekt odešle signál přes publisher objectWillChange, což spustí překreslení všech View, která tento objekt pozorují.
SwiftUI ukládá instanci ObservableObject do speciálního úložiště vázaného na konkrétní instanci View. Toto úložiště je vytvořeno jednou při prvním renderování a existuje až do zničení View. Právě proto @StateObject zaručuje stabilitu reference na objekt — SwiftUI spravuje paměť automaticky, aniž by se spoléhal na inicializátor View.
Podle objc.io — Thinking in SwiftUI (2025) používá interní implementace @StateObject mechanismus podobný @State, ale pro referenční typy: SwiftUI vytváří boxing obal kolem objektu a spravuje jeho životní cyklus prostřednictvím vlastního alokátoru, optimalizovaného pro časté přestavby hierarchie View.
Hlavní rozdíl mezi @StateObject a @ObservedObject spočívá v tom, kdo objekt vlastní. @StateObject vytváří a ukládá objekt — je vlastníkem. @ObservedObject pouze pozoruje objekt, který byl vytvořen jinde a předán prostřednictvím inicializátoru nebo vlastnosti.
| Vlastnost | @StateObject | @ObservedObject |
|---|---|---|
| Vlastnictví | Vytváří a vlastní objekt | Pouze pozoruje |
| Inicializace | Uvnitř View pomocí init/default | Zvenčí, předáno parametrem |
| Životní cyklus | Vázán na životní cyklus View | Není řízen View |
| Znovuvytvoření | Při aktualizaci není znovu vytvářen | Může být nahrazen zvenčí |
| Verze iOS | iOS 14+ | iOS 13+ |
Pravidlo je jednoduché: pokud View vytváří ObservableObject — použij @StateObject. Pokud View pouze přijímá již hotový objekt od rodiče — použij @ObservedObject. Porušení tohoto pravidla vede buď ke ztrátě dat (pokud použijete @ObservedObject pro vlastnictví), nebo k nadměrnému vytváření objektů (pokud použijete @StateObject pro pozorování).
@StateObject by měl být použit v těch View, která jsou zdrojem pravdy pro určitou sadu dat. Typické scénáře zahrnují obrazovky s vlastním view modelem, kořenové obrazovky navigačních zásobníků a modální prezentace spravující vlastní stav.
struct ProfileView: View {
@StateObject var viewModel = ProfileViewModel()
var body: some View {
NavigationStack {
Form {
TextField("Name", text: $viewModel.name)
TextField("Email", text: $viewModel.email)
Button("Uložit") {
viewModel.saveProfile()
}
}
.navigationTitle("Profile")
}
}
}
Inicializace @StateObject s parametry vyžaduje speciální syntaxi, protože SwiftUI spravuje vytváření objektu nezávisle. Nelze jednoduše předat parametry inicializátoru — je třeba použít escaping closure nebo samostatnou metodu vytvoření.
Podle Swift by Sundell (2024) je nejčistší metodou použití tovární metody nebo closure, kterou SwiftUI zavolá při prvním vytvoření objektu. Alternativní přístup — inicializovat ObservableObject v nadřazeném View a předat jej prostřednictvím @StateObject pomocí standardního inicializátoru.
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)
}
}
Je důležité si pamatovat, že inicializátor View s @StateObject musí používat podtržítko před názvem vlastnosti (_viewModel) pro přístup k samotnému property wrapperu, nikoli k jeho hodnotě. Toto je standardní vzor Swift pro práci s property wrappery v inicializátorech.
Nejčastější chybou je použití @ObservedObject místo @StateObject pro View, které by mělo objekt vlastnit. V tomto případě bude při každé přestavbě rodiče objekt znovu vytvořen, což vede ke ztrátě všech nashromážděných dat. Tato chyba je obzvláště záludná ve složitých hierarchiích s NavigationStack nebo TabView.
Abyste se těmto problémům vyhnuli, dodržujte jednoduché pravidlo: jeden @StateObject na jeden zdroj pravdy. Pokud mají být data sdílena mezi více obrazovkami — vytvořte @StateObject jednou v kořenovém View a předávejte jej prostřednictvím @ObservedObject nebo @EnvironmentObject podřízeným prvkům.
// ❌ Špatně: @ObservedObject pro vlastnictví objektu
struct BadView: View {
@ObservedObject var vm = ViewModel() // bude znovu vytvořen při každé aktualizaci!
}
// ✅ Správně: @StateObject pro vlastnictví
struct GoodView: View {
@StateObject var vm = ViewModel() // vytvořen jednou pro dobu života View
}
Často kladené dotazy
@State pracuje s hodnotovými typy (struktury, řetězce, čísla) a ukládá hodnotu přímo do úložiště SwiftUI. @StateObject pracuje s referenčními typy — třídami vyhovujícími ObservableObject. @State je vhodný pro jednoduché lokální stavy, @StateObject pro složité objekty s logikou a publikovanými vlastnostmi.
Ne, @StateObject je dostupný pouze od iOS 14 výše. Pro iOS 13 použijte @ObservedObject a vytvářejte ObservableObject v nadřazeném View pomocí @State s ruční správou životního cyklu. Alternativou je použití @State se struct místo class pro data, která nevyžadují referenční sémantiku.
Podřízené View vytvoří svou vlastní kopii ObservableObject, zcela nezávislou na rodičovské. Změny v jedné se neprojeví v druhé. To je téměř vždy chyba: použijte @ObservedObject pro příjem objektu od rodiče a @StateObject pouze pro vytvoření nového objektu uvnitř View.
Objekt je zničen, když View, které jej vytvořilo, je zcela odstraněno z hierarchie SwiftUI. Pro obrazovku v NavigationStack k tomu dochází při popu z navigačního zásobníku. Pro modální okno — při jeho zavření. Pro TabView — při přepnutí karty, pokud View není ukládáno do mezipaměti.
Použijte vlastní init s přístupem k property wrapperu přes podtržítko: _viewModel = StateObject(wrappedValue: MyViewModel(param: value)). Tento vzor umožňuje předat libovolné parametry ObservableObject při zachování záruky jediného vytvoření objektu po dobu života View.
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é