ObservableObject
is a great tool for this. You can make one ObservableObject
and have it owned by the common ancestor of the subviews and cell views.
Here's a basic example:
class StateManager : ObservableObject {
@Published var counter = 0
}
struct ContentView : View {
@ObservedObject var state = StateManager()
var body: some View {
TabView {
Page1(state: state).tabItem { Text("Tab 1") }
Page2(state: state).tabItem { Text("Tab 2") }
}
}
}
struct Page1 : View {
@ObservedObject var state : StateManager
var body: some View {
Subview(state: state)
}
}
struct Subview : View {
@ObservedObject var state : StateManager
var body : some View {
Button(action: { state.counter += 1 }) {
Text("Increment: \(state.counter)")
}.foregroundColor(.purple)
}
}
struct Page2 : View {
@ObservedObject var state : StateManager
var body: some View {
Subview2(state: state)
}
}
struct Subview2 : View {
@ObservedObject var state : StateManager
var body : some View {
Button(action: { state.counter -= 1 }) {
Text("Decrement: \(state.counter)")
}.foregroundColor(.red)
}
}
I passed the ObservableObject
explicitly as a property to each view, but you could also look into doing this with .environmentObject
.
Note that this is not the only solution to this. You could also accomplish this with a shared @State
and Bindings
, but those look like they may be unreliable as they are passed through multiple levels of a view hierarchy, where as the solution I show here is stable and an extremely common way of solving this sort of problem in SwiftUI.