Publisher inside a Publisher does not trigger SwiftUi re-render

做~自己de王妃 提交于 2020-02-05 04:26:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!