从ObservableObject发布者更新状态

时间:2020-04-23 00:43:55

标签: swift swiftui reactive-programming swift5

我正在尝试使用Combine和SwiftUI,但基本上停留在更新状态,我想每次ObservableObject更改时都在视图中更新状态, 这是示例。

class XViewModel: ObservableObject {
    @Published var tVal: Bool = false
    private var cancellables = Set<AnyCancellable>()

    func change() {
        Just(true)
            .delay(for: 3.0, scheduler: RunLoop.main)
            .receive(on: RunLoop.main)
            .assign(to: \.tVal, on: self)
            .store(in: &self.cancellables)
    }
}

我有viewModel以及一个发布者和一个延迟发布者,它们在3秒后触发。

struct ContentView: View {
    @ObservedObject var viewModel = XViewModel()
    @State var toggleVal: Bool = false
    private var cancellables = Set<AnyCancellable>()

    init() {
        self.viewModel.$tVal
            .sink { newVal in
            print(newVal)
        }
        .store(in: &cancellables)        

        self.viewModel
            .$tVal.assign(to: \.toggleVal, on: self)
            .store(in: &cancellables)

        viewModel.change()
    }

    var body: some View {
        VStack {
            Toggle(isOn: self.$viewModel.tVal) {
                Text("Toggle")

            Toggle(isOn: self.$toggleVal) {
                Text("Toggle from View")
            }
    }

}

我期望的是

viewModel.Just triggers
viewModel.tVal publisher triggers
view.toggleVal state triggers 
updates UI 

但是,尽管一切都已更新,但似乎并没有更新状态。有什么方法可以更新State,或者根本不打算更新它,我需要将我的视图直接绑定到viewModel的tVal值(即发布者)。

谢谢。

1 个答案:

答案 0 :(得分:1)

@State中的init尚未准备好运行,请改为使用.onReceive,如下所示。

struct ContentView: View {
    @ObservedObject var viewModel = XViewModel()
    @State var toggleVal: Bool = false
    private var cancellables = Set<AnyCancellable>()

    init() {
        self.viewModel.$tVal
            .sink { newVal in
            print(newVal)
        }
        .store(in: &cancellables)        

        viewModel.change()
    }

    var body: some View {
        VStack {
            Toggle(isOn: self.$viewModel.tVal) {
                Text("Toggle")

            Toggle(isOn: self.$toggleVal) {
                Text("Toggle from View")
            }
            .onReceive(self.viewModel.$tVal) { newVal in // << here !!
                self.toggleVal = newVal
            }
    }

}