@StateObject: co to je, rozdíl od @ObservedObject a příklady

Autor: IT Sectr Publikováno: 2026-06-19 Doba čtení: 7 min

@StateObject je Property Wrapper ve SwiftUI pro vytvoření a vlastnictví instance ObservableObject přímo ve view. SwiftUI zaručuje, že objekt je inicializován jednou za životní cyklus zobrazení a není znovu vytvářen při opakovaných renderech. Podle Apple Developer Documentation (2025) je @StateObject doporučen pro kořenová view vytvářející zdroj dat. @StateObject je správná volba pro vlastnictví ObservableObject v hierarchii SwiftUI.

Hlavní body

  • @StateObject — Property Wrapper pro vytvoření a vlastnictví ObservableObject ve view
  • Jediná instance — objekt je vytvořen jednou a není znovu vytvářen při renderech
  • Zdroj pravdy — @StateObject zaručuje stabilitu dat pro celou hierarchii
  • Rozdíl od @ObservedObject — @ObservedObject objekt nevlastní a může ho ztratit
  • Kořenová view — @StateObject se používá ve view, které objekt vytváří

Co je @StateObject ve SwiftUI?

@StateObject je Property Wrapper, který se objevil ve SwiftUI 2.0 (iOS 14) a kombinuje možnosti @ObservedObject a @State. Stejně jako @ObservedObject se přihlašuje ke změnám ObservableObject. Stejně jako @State zaručuje, že data přežijí vícenásobné inicializace struktury view. @StateObject vytváří objekt jednou při prvním zobrazení view na obrazovce a ukládá ho na haldě SwiftUI.

Před příchodem @StateObject používali vývojáři @ObservedObject pro všechny ObservableObject, včetně těch vytvořených ve view. To vedlo k časté ztrátě dat při aktualizaci nadřazeného view, kdy byla struktura view znovu vytvořena a vzala s sebou i instanci @ObservedObject. @StateObject vyřešil tento problém přidáním záruky stability.

Základní pravidlo: @StateObject se aplikuje ve view, které vytváří objekt ve výchozím inicializátoru (let model = ViewModel()). Dceřiná view, která tento objekt přijímají, používají @ObservedObject. Takové rozdělení zaručuje jediný zdroj pravdy v celé hierarchii.

Životní cyklus @StateObject

SwiftUI spravuje životní cyklus @StateObject prostřednictvím správce úložiště, analogicky k @State. Při prvním zobrazení view SwiftUI alokuje paměť pro objekt a uloží ho do persistentní oblasti. Při opakovaných renderech (volání body) není objekt znovu vytvářen — používá se existující instance. Objekt žije, dokud je view v hierarchii.

Když je view odstraněno z hierarchie, SwiftUI zničí @StateObject a zavolá deinit. Při opětovném přidání view do hierarchie je vytvořena nová instance. To je důležité vzít v úvahu při návrhu: pokud potřebujete uchovat data mezi odstraněními view, použijte servisní vrstvu (singleton nebo DI) nebo @AppStorage pro perzistenci.

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() }
    }
}

V příkladu je TimerViewModel vytvořen přes @StateObject a žije, dokud je TimerView na obrazovce. Timer se spouští v onAppear a zastavuje v deinit. Pokud by byl použit @ObservedObject, při každém renderu TimerView by byl vytvořen nový TimerViewModel s sekundami = 0 a timer by nikdy nepracoval správně. @StateObject zaručuje, že viewModel je jedinečný a stabilní.

@StateObject vs @ObservedObject: srovnání

Výběr mezi @StateObject a @ObservedObject závisí na tom, kdo vlastní objekt. Pokud view vytváří objekt — @StateObject. Pokud view přijímá hotový objekt — @ObservedObject. Toto pravidlo je tak důležité, že Xcode vydává varování při použití @StateObject v dceřiném view, které přijímá objekt přes inicializátor.

SituaceDoporučený wrapper
View vytváří model přes ViewModel()@StateObject
View přijímá model od rodiče@ObservedObject
Model je použit v jednom view@StateObject
Model je předáván přes Environment@EnvironmentObject
Model je potřeba pro náhled@ObservedObject + mock

V praxi se na začátku projektu často používá @StateObject v kořenovém view a @ObservedObject ve všech dceřiných view. Jak aplikace roste, část @StateObject může být nahrazena @EnvironmentObject pro zjednodušení hierarchie. @StateObject však zůstává nejlepší volbou pro modulární obrazovky s vlastní logikou.

Vzory použití @StateObject

První vzor — MVVM s @StateObject. ViewModel jako ObservableObject je vytvořen ve view přes @StateObject. ViewModel obsahuje @Published vlastnosti a obchodní logiku. View se přihlašuje ke změnám a aktualizuje rozhraní. Tento přístup poskytuje testovatelnou izolaci: ViewModel lze testovat bez UI vytvořením instance přímo.

Druhý vzor — @StateObject se závislostmi. Pokud ViewModel vyžaduje služby, použijte inicializaci s parametry. Například @StateObject var viewModel = UserViewModel(api: APIClient.shared). Buďte však opatrní: parametry se vypočítávají při každém renderu body, ale objekt je vytvořen pouze jednou. SwiftUI ignoruje následné inicializace @StateObject.

Třetí vzor — vnořené @StateObject. Ve SwiftUI můžete mít více @StateObject v jednom view, ale je to zřídka oprávněné. Obvykle jeden @StateObject odpovídá za celou sadu dat view. Pokud je logika příliš složitá, rozdělte ji na kompozici @ObservedObject služeb v rámci jednoho @StateObject.

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

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

V příkladu AppView vytváří dva @StateObject: NavigationRouter pro správu navigace a AuthViewModel pro autentizaci. Oba objekty jsou injektovány do Environment přes environmentObject. Libovolné dceřiné view k nim může přistupovat přes @EnvironmentObject bez předávání přes řetězec inicializátorů.

@StateObject a inicializace s parametry

@StateObject podporuje inicializaci s libovolnými parametry, ale s důležitou vlastností: inicializátor je volán pouze jednou. Při opakovaných renderech body je nová hodnota parametrů ignorována. To znamená, že pokud předáte @State var id: Int = 5 do @StateObject var vm = ViewModel(id: id), při změně id ViewModel neobdrží novou hodnotu.

Pro vyřešení tohoto problému použijte onReceive nebo onAppear pro synchronizaci. Přihlaste se ke změnám parametru uvnitř ViewModel přes Combine nebo předávejte parametry přes metodu .onChange(of:) na úrovni view. Alternativa — použijte @ObservedObject místo @StateObject, pokud má objekt dynamicky reagovat na vnější změny.

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

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

Správný přístup: DetailView přijímá itemId jako let vlastnost (předanou přes inicializátor struktury) a @StateObject vytváří DetailViewModel bez parametrů. V onAppear je volána metoda load(id:), která načítá data pro předané ID. To zaručuje, že ViewModel je vytvořen mechanismem @StateObject, ale data jsou načítána při každém zobrazení view s aktuálním ID.

Typické chyby s @StateObject

Hlavní chyba — použití @StateObject v dceřiných view, která přijímají objekt od rodiče. Pokud ParentView vytváří @StateObject model a ChildView deklaruje @StateObject var model: ModelType (s výchozím parametrem), ChildView vytvoří vlastní nezávislou instanci. Objekty rodiče a dítěte nebudou propojeny a změny v jednom se neprojeví v druhém.

Druhá chyba — umístění @StateObject v List nebo ForEach. Každý prvek seznamu vytváří svůj vlastní @StateObject, což vede k mnoha nezávislým instancím. Pro seznamy je správné předat jeden ObservableObject všem prvkům přes @ObservedObject nebo použít Identifiable struktury s @State uvnitř List.

Třetí problém — chybějící čištění v deinit. @StateObject žije po celý životní cyklus view. Pokud objekt vytváří časovače, Combine předplatná nebo síťové požadavky, deinit je musí zrušit. Jinak jsou nevyhnutelné úniky paměti a pokračování práce na pozadí po zavření obrazovky. Vždy používejte Combine Cancellable store nebo invalidate časovačů v deinit.

Často kladené otázky

Kdy se objevil @StateObject ve SwiftUI?

@StateObject byl přidán ve SwiftUI 2.0 na WWDC 2020 spolu s iOS 14, macOS 11, watchOS 7 a tvOS 14. Předtím byl @ObservedObject jediným způsobem práce s ObservableObject, což vedlo k častým chybám se ztrátou dat.

Může být @StateObject volitelný?

Ne, @StateObject nepodporuje typy Optional. Objekt musí být inicializován při deklaraci. Pokud potřebujete volitelný objekt, použijte @ObservedObject nebo @EnvironmentObject s volitelným typem.

Jak zkontrolovat, že @StateObject je vytvořen pouze jednou?

Přidejte print(#function) do inicializátoru a deinit ObservableObject. Pokud se init nevolá při opakovaných renderech — @StateObject funguje správně. Pokud se init volá pokaždé — nahraďte @ObservedObject za @StateObject.

Lze použít @StateObject s UIKit přes UIHostingController?

Ano, @StateObject funguje ve SwiftUI view vložených do UIKit přes UIHostingController. Životní cyklus objektu je vázán na SwiftUI view, nikoli na UIViewController. Pokud je SwiftUI view nahrazeno, @StateObject je zničen.

Co je lepší: jeden @StateObject s velkým ViewModel nebo několik malých?

Několik malých @StateObject s rozdělenou odpovědností. To zlepšuje testovatelnost, znovupoužitelnost a výkon — při změně jednoho objektu se překreslí pouze přihlášené části rozhraní, nikoli celé view.

Shrnutí

  • @StateObject — Property Wrapper pro vytvoření a vlastnictví ObservableObject ve view
  • Jediná instance — objekt není znovu vytvářen při opakovaných renderech body
  • Zdroj pravdy — @StateObject v kořenovém view zaručuje stabilitu dat pro hierarchii
  • Pravidlo výběru — @StateObject pro vytvoření, @ObservedObject pro přijetí hotového objektu
  • Inicializace — parametry v @StateObject se počítají jednou, aktualizace nejsou sledovány
  • Deinit — povinné čištění časovačů a předplatných v deinit ObservableObject
  • iOS 14+ — @StateObject dostupný od iOS 14, macOS 11, watchOS 7, tvOS 14

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í.

Prodiskutovat projekt

Přečtěte si také