发布者内部的发布者不会触发SwiftUi重新渲染

时间:2019-12-23 08:24:45

标签: swift swiftui combine

我在EnvironmentObject中为我的应用程序创建了一个“状态”对象 像这样:

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

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

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

计数器是后台任务

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)
        }
    }  
}

在我看来,我有:

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)
            }
        }
    }
}

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

如何在不将计数器移入View或在状态对象中实现计数器的情况下解决此问题?

1 个答案:

答案 0 :(得分:2)

您的假设不正确。您将Counter设置为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.$ammount, perform: { value in
                self.currentCounter = value.description
            })
        }
    }
}