I’m developing an iOS app using SwiftUI and I’ve hit a road block and wondering if anyone can help me.
I have a main view(ContentView) with 4 subviews within it. The main view has info coming in from a class where all the data is stored and the data is updated from the subviews.
On one of the subviews, I have a button that calls a function updating the data in the class, though the main view is not picking it up. The function is being called and if I reset the app the data has been updated and shows on the main view.
It’s just not picking it up. I have tried having the data as an ObservableObject but still not picking up the changes when the function is run.
Please see the code below and please help, it’s driving me nuts.
This is the main ContentView
import SwiftUI
struct ContentView: View {
@ObservedObject var gameState = GameState()
var body: some View {
ZStack {
VStack {
Text(String(gameState.points))
// Other view content
TabView {
UpgradeView() // This is where the subview appears and looks to be fine
.tabItem {
Image(systemName: "rectangle.and.hand.point.up.left.fill")
Text("Upgrades")
}
// Other tab content
.tabItem {
Image(systemName: "cpu")
Text("Bots")
}
// Other tab content
.tabItem {
Image(systemName: "gear")
Text("Settings")
}
}
}
} // ZStack
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This is the class (GameState)
import Foundation
class GameState: ObservableObject {
//This number is showing on the main ContentView but when the function is called from the subview.
It doesn't update on ContentView. It does print in console though when ran so it is working.
@Published var points = 5
@Published var pointsPerSecond = 10
init(){
}
func doublePoints() {
var runCount = 0
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timerEnd in
self.points = self.pointsPerSecond
print(self.points)
runCount = 1
if runCount == 30 {
timerEnd.invalidate()
}
})
}
}
This is the Subview
import SwiftUI
struct UpgradesView: View {
@ObservedObject var gameState = GameState()
var body: some View {
HStack {
Button(action: {
gameState.doublePoints() // This is the function called in the from the gameState class, this works
}) {Image(systemName: "arrow.up.circle.fill")
.font(.system(size: 40))
}
}
}
}
struct UpgradesView_Previews: PreviewProvider {
static var previews: some View {
UpgradesView()
}
}
CodePudding user response:
Your subview is observing a different instance of your class. Note how, in both views, you're doing:
@ObservedObject var gameState = GameState()
This is creating a separate instance each time.
What you want is for your subview to use the same instance as your parent view.
One option is to inject the instance from the parent view into the environment of its view:
UpgradeView()
.environmentObject(gameState)
And then, in UpgradeView
, change it from an observed object to
@EnvironmentObject var gameState: GameState
This will now get the instance out of the environment, which will be the same instance as the parent.