-1

I've tried looking around at State and ObservableObject solutions to this but I need some help.

Essentially I have in my ContentView a tabView with 2 tabs in it, say subview1 and subview2. Both subviews also contain another view called cellView. When the cellView is altered in one subview I want to make the other redraw.

Layout example:

              TabView
             +         +
             |         |
             |         |
Subview1  <--+         +--> Subview2
    +                        +
    |                        |
    v                        v
  CellView                  CellView

I feel it should be easy but I can't get it working with @State vars or anything.

1 Answers1

1

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.

jnpdx
  • 45,847
  • 6
  • 64
  • 94