Ovy MC
Ovy MC

Reputation: 89

SwiftUI @ObservedObect not updating

I have a content view where I'm displaying or not a Text based on a boolean that I get from Firebase RemoteConfig. I'm trying to pass the boolean on SecondView and I want it to be update himself when the boolean on ContentView is updating.

class GlobalString: ObservableObject {
    @Published var isHidden = true
}

struct ContentView: View {
    @ObservedObject var globalString = GlobalString()
    
func updateUI(newUI: Bool) {
    if newUI {
        globalString.isHidden = false
    }
    else {
        globalString.isHidden = true
    }
}
func fetchValues() {
        let value = self.remoteConfig.configValue(forKey: "show_boost").boolValue
        updateUI(newUI: value)
    }
    
    init() {
        fetchValues()
    }
    
    var body: some View {
    if !globalString.isHidden {
        Text("Not Hidden")
    else {
        Text("Hidden")
    }
  }
}

The thing is that my Boolean in my SecondView is not updating when I change the boolean on ContentView (via RemoteConfig). And I don't know why...

struct SecondView: View {
    
    @ObservedObject var globalString = GlobalString()

    var body: some View {
        VStack {
            if globalString.isHidden {
                Text("Hidden")
            else {
                Text("Not Hidden")
            }
         }
     }
  }
}

Upvotes: 0

Views: 314

Answers (1)

lorem ipsum
lorem ipsum

Reputation: 29261

Each one of these @ObservedObject var globalString = GlobalString() is a separate instance of your global model.

One cannot see what the other is doing.

class GlobalString: ObservableObject {
    @Published var isHidden = true
    
    init() {
        fetchValues()
    }
    //This kind of stuff shouldn't be in a View it can't be shared/reused.
    func fetchValues() {
        let value = self.remoteConfig.configValue(forKey: "show_boost").boolValue
        updateUI(newUI: value)
    }
    
    func updateUI(newUI: Bool) {
        if newUI {
            self.isHidden = false
        }
        else {
            self.isHidden = true
        }
    }
}
struct SampleUpdateParentView: View {
    //@ObservedObject is for when then instance is initialized in another View
    @StateObject var globalString = GlobalString()
    
    var body: some View {
        //This is how you share an instance
        SampleUpdateView().environmentObject(globalString)
        SecondView().environmentObject(globalString)
    }
}
struct SampleUpdateView: View {
    @EnvironmentObject var globalString: GlobalString
    var body: some View {
        if !globalString.isHidden {
            Text("Not Hidden")
        }else {
            Text("Hidden")
        }
    }
}
struct SecondView: View {
    @EnvironmentObject var globalString: GlobalString
    
    var body: some View {
        VStack {
            if globalString.isHidden {
                Text("Hidden")
            }else {
                Text("Not Hidden")
            }
        }
    }
}

You can also use a singleton (less recommended) just change/replace your init in your class GlobalString too

static let shared = GlobalString()
private init() {
    fetchValues()
}

And change your instances to reference the shared variable.

@StateObject var globalString = GlobalString.shared

Upvotes: 1

Related Questions