Reputation: 26223
If you wanted to pass a model between multiple views can you use @StateObject multiple times (see example below) so that each view can modify the object? I appreciate that this would be better done using @EnvironmentObject but was just trying to understand how this new property wrapper works in this situation.
// MARK: - MODEL
class Model: ObservableObject {
@Published var temperature = 27.5
}
.
// MARK: - APP.SWIFT
@main
struct SwiftUI_DataFlow_005App: App {
@ObservedObject var model = Model()
var body: some Scene {
WindowGroup {
ContentView(model: model)
}
}
}
.
// MARK: - CONTENT VIEW
struct ContentView: View {
@StateObject var model: Model
var body: some View {
VStack {
Text("\(model.temperature)")
AnotherView(model: model)
}
}
}
// MARK: - ANOTHER VIEW
struct AnotherView: View {
@StateObject var model: Model
var body: some View {
Text("\(model.temperature)")
}
}
Upvotes: 7
Views: 7690
Reputation: 257573
@StateObject
is source of truth, so it must be created in one place, so (schematically as you provided screenshot, but not a code to modify)
in App >
@StateObject private var model = Model()
...
ContentView().environmentObject(model)
...
in ContentView >
@EnvironmentObject var model: Model
...
in AnotherView >
@EnvironmentObject var model: Model
Upvotes: 9
Reputation: 26223
A small expansion based on the accepted answer so future readers can gain a little more insight.
1 - @ObservedObject
APPLE: Managing Model Data in Your App
It would seem from the Apple docs that one solution would be to use @ObservedObject on all three views.
// MARK: - CONTENT VIEW
struct ContentView: View {
@ObservedObject var model: Model
var body: some View {
VStack {
Text("\(model.temperature)")
AnotherView(model: model)
}
}
}
.
// MARK: - ANOTHER VIEW
struct AnotherView: View {
@ObservedObject var model: Model
var body: some View {
Text("\(model.temperature)")
}
}
2 - @EnvironmentObject
Another solution @asperi and by far the simplest is to create the model in app.swift as @StateObject and then inject the object into the environment. This then means you don't have to pass the model through the hierarchy, but rather access it as needed using @EnviromentObject.
// MARK: - APP.SWIFT
@main
struct SwiftUI_DataFlow_005App: App {
@StateObject var model = Model()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(model)
}
}
}
.
// MARK: - CONTENT VIEW
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
VStack {
Text("\(model.temperature)")
AnotherView()
}
}
}
.
// MARK: - ANOTHER VIEW
struct AnotherView: View {
@EnvironmentObject var model: Model
var body: some View {
Text("\(model.temperature)")
}
}
Upvotes: 7