Structure¶
StateObject¶
A SwiftUI property wrapper that instantiates and stores an observable object in state.¶
Declaration¶
@frozen @propertyWrapper struct StateObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject
Overview¶
- Think of @StateObject as a combination of @State and @ObservedObject.
- Like @ObservedObject, this type subscribes to the observable object and invalidates a view whenever the observable object changes.
- Unlike @ObservedObject, @StateObject holds on to its value even when the view is invalidated and redrawn.
Usage¶
In the following example, an observable object class AppModel is instantiated and stored in a @StateObject:
class AppModel: ObservableObject {
@Published var foo: Bool = false
}
struct ExampleView: View {
@StateObject var appModel = AppModel()
var body: some View {
Text("Hello World")
}
}

How it works¶
The following is the basic structure of a @StateObject:
struct StateObject<ObjectType: ObservableObject>: DynamicProperty {
var wrappedValue: ObjectType { get }
init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType)
}
@StateObject var appModel = AppModel()
Creating bindings¶
Just like @State, @ObservedObject and @EnvironmentObject, @StateObject allows you to create a Binding from its wrapped value type using the $ syntax.
For example:
class AppModel: ObservableObject {
@Published var flag: Bool = false
}
struct ExampleView: View {
@StateObject var appModel = AppModel()
var body: some View {
Toggle("Flag", isOn: $appModel.flag)
}
}

In this example, AppModel contains a boolean, flag, which is represented by a Toggle in ChildView. Toggle requires a Binding
Comparison with @ObservedObject¶
Consider the following:
struct ExampleView: View {
class ViewModel: ObservableObject {
init() {
print("Initialized")
}
}
struct ToggleDescription: View {
let value: Bool
@StateObject var viewModel = ViewModel()
var body: some View {
Text("The value is: \(String(describing: value))")
}
}
@State var foo = false
var body: some View {
VStack {
ToggleDescription(value: foo)
Toggle("Refresh", isOn: $foo)
}
}
}

ExampleView creates a vertical stack of a Toggle, and a view that describes the toggle, ToggleDescription.
ToggleDescription also contains a ViewModel, that is instantiated and held by @StateObject. The ViewModel prints on initialization. Run this code and observe that the following is printed:
Flip the toggle twice. Note that even though ToggleDescription is refreshed, nothing is printed further.
Now consider the following:
struct ExampleView: View {
class ViewModel: ObservableObject {
init() {
print("Initialized")
}
}
struct ToggleDescription: View {
let value: Bool
@ObservedObject var viewModel = ViewModel()
var body: some View {
Text("The value is: \(String(describing: value))")
}
}
@State var foo = false
var body: some View {
VStack {
ToggleDescription(value: foo)
Toggle("Refresh", isOn: $foo)
}
}
}

This example is identical to the previous example except for the fact that @StateObject has been replaced with @ObservedObject. Run this code now, and observe the following print again:
Initialized
Initialized
Initialized
Initialized
- @StateObject instantiates and holds the object in state
- @ObservedObject is assigned an object, and does not hold it in
Usage with App¶
@StateObject provides a great way to initialize global, application-wide models.
In the following example, a @StateObject is instantiated in MyApp, and passed down to ExampleView as an environment object.
class AppModel: ObservableObject {
@Published var foo: Bool = false
}
@main
struct MyApp: App {
@StateObject var appModel = AppModel()
var body: some Scene {
WindowGroup {
ExampleView()
.environmentObject(appModel)
}
}
}
struct ExampleView: View {
@EnvironmentObject var appModel: AppModel
var body: some View {
Text("Hello World")
}
}

Availability¶
iOS 14.0+
macOS 11.0+
tvOS 14.0+
watchOS 7.0+
Topics¶
Instance Property¶
projectedValue A projection of the state object that creates bindings to its properties.
wrappedValue The underlying value referenced by the state object.
Initializer¶
init(wrappedValue:) Creates a new state object with an initial wrapped value.