Обновление состояния от издателя ObservableObject - PullRequest
1 голос
/ 23 апреля 2020

Я экспериментировал с 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 или его не нужно было обновлять вообще, и мне нужно привязать мои представления непосредственно к значению tVal viewModel, являющемуся издателем.

Спасибо.

1 Ответ

1 голос
/ 23 апреля 2020

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

}
...