I have an app that depends on a model which displays quite different screens depending on current state. Here’s a simple minimum example WHICH WORKS to illustrate the idea. The model is observed via @StateObject and the ContentView() simply switches on state.
In my real model, each display is more complex so it makes sense to drop them into separate structs, but when I do, they seem to lose track of state. This is also illustrated below in my very simple example. What am I doing wrong?
Working Version of ContentView()
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
Group {
switch viewModel.state {
case .A: VStack {
Text("Showing A")
Button("Change") {
viewModel.changeState(.B)
}
}
case .B: VStack {
Text("Showing B")
Button("Change") {
viewModel.changeState(.C)
}
}
case .C: VStack {
Text("Showing C")
Button("Change") {
viewModel.changeState(.A)
}
}
}
}.environmentObject(viewModel)
}
}
Broken Version of ContentView()
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
Group {
switch viewModel.state {
case .A: AView()
case .B: BView()
case .C: CView()
}
}.environmentObject(viewModel)
}
}
struct AView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
VStack {
Text("Showing A")
Button("Change") {
viewModel.changeState(.B)
}
}
}
}
struct BView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
VStack {
Text("Showing B")
Button("Change") {
viewModel.changeState(.C)
}
}
}
}
struct CView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
VStack {
Text("Showing C")
Button("Change") {
viewModel.changeState(.A)
}
}
}
}
The Model and the ViewModel:
struct Model {
var state:State = .A
}
enum State: String {
case A
case B
case C
}
class ViewModel: ObservableObject {
@Published var model = Model()
var state: State { return model.state }
func changeState(_ state: State) {
model.state = state
}
}