问题
I made a "State" Object for my App in EnvironmentObject Like this:
class AppState: ObservableObject {
@Published var counter = Counter()
}
To add this to my App I use:
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(state))
The counter is a background task
class Counter: ObservableObject {
@Published var ammount: Double
var timer = Timer()
init() {
self.ammount = 0.0
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(setCoords), userInfo: nil, repeats: true)
}
@objc private func setCoords() {
DispatchQueue.main.async() { () -> Void in
self.ammount = self.ammount + 0.1
print(self.ammount)
}
}
}
And in my View I have:
struct ContentView: View {
@EnvironmentObject var state: AppState
@State var isVisible = true
var body: some View {
VStack {
Button(action: {
self.isVisible.toggle()
}) {
Text("Button")
}
if isVisible {
Text(state.counter.ammount.description)
}
}
}
}
So basically, what I was hoping was that I see the counter in my UI update after every second. But the UI does not update. I see the print statement fire every second and if I trigger the UI update from the UI Button self.isVisible.toggle()
then the counter will also update.
How could I solve this problem without moving the counter into the View or implementing it in the state object?
回答1:
Your assumption is not correct. You made Counter
as ObservableObject
, but never observe it.
Making state
as @EnvironmentObject
you observe changes of property var counter
, but not inside it. It is class, reference type, not struct, so modifications of internal properties of instance does not result in modification of the instance itself - the reference remains the same, so state
is not changed.
Here is one of the approach to make your snapshot working - by introducing explicit publisher events observing and update dependent local view state:
@State var currentCounter: String = ""
var body: some View {
VStack {
Button(action: {
self.isVisible.toggle()
}) {
Text("Button")
}
if isVisible {
Text(currentCounter)
.onReceive(state.counter.$ammount, perform: { value in
self.currentCounter = value.description
})
}
}
}
来源:https://stackoverflow.com/questions/59452113/publisher-inside-a-publisher-does-not-trigger-swiftui-re-render