问题
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