首页 > 解决方案 > Publisher 中的 Publisher 不会触发 SwiftUi 重新渲染

问题描述

我在 EnvironmentObject 中为我的应用程序创建了一个“状态”对象,如下所示:

class AppState: ObservableObject {
    @Published var counter = Counter()
}

要将其添加到我的应用程序中,我使用:

window.rootViewController = UIHostingController(rootView: contentView.environmentObject(state))

计数器是后台任务

class Counter: ObservableObject {
    
    @Published var amount: Double
    
    var timer = Timer()
    
    init() {
        self.amount = 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.amount = self.amount + 0.1
            print(self.amount)
        }
    }  
}

在我看来,我有:

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.amount.description)
            }
        }
    }
}

所以基本上,我希望每秒钟都能在我的 UI 更新中看到计数器。但是 UI 没有更新。我看到打印语句每秒触发一次,如果我从 UI 按钮触发 UI 更新,self.isVisible.toggle()那么计数器也会更新。

如果不将计数器移动到视图中或在状态对象中实现它,我该如何解决这个问题?

标签: swiftswiftuicombine

解决方案


你的假设是不正确的。你做了Counteras ObservableObject,但从不观察它。

state@EnvironmentObject你观察属性的变化时进行制作var counter,但不是在它里面。它是类,引用类型,而不是结构,因此修改实例的内部属性不会导致修改实例本身 - 引用保持不变,因此state不会改变。

这是使您的快照工作的方法之一 - 通过引入显式发布者事件来观察和更新相关的本地视图状态:

@State var currentCounter: String = ""
var body: some View {
    VStack {
        Button(action: {
            self.isVisible.toggle()
        }) {
           Text("Button")
        }
        if isVisible {
            Text(currentCounter)
            .onReceive(state.counter.$amount, perform: { value in
                self.currentCounter = value.description
            })
        }
    }
}

推荐阅读