RxSwift:如何正确订阅变量变化

RxSwift: How to correctly subscribe to a variable change

我有两个屏幕:

  1. NewControlTableViewController: 包含一个用于从另一个视图中选择客户端的文本字段
  2. ClientsTableViewController: 第二个视图包含一个可以选择的客户列表

两个屏幕共享一个viewmodel。

所以这是我的代码:

import RxSwift
import RxCocoa
struct NewControlViewModel {
     var selectedClient = Variable<Client>(Client())
     // other stuff
}
// NewControlTableViewController : viewDidLoad
viewModel.selectedClient.asObservable().subscribe { event in
        debugPrint(event)
}
// ClientsTableViewController: viewDidLoad

/*tableView.rx.itemSelected.subscribe(onNext: { indexPath in
        let client = self.clients[indexPath.row]
        debugPrint(client)
        self.viewModel.selectedClient.value = client
        self.navigationController?.popToRootViewController(animated: true)

    }).disposed(by: self.disposeBag)*/
   // new code
   tableView.rx
        .modelSelected(Client.self)
        .debug("client selected", trimOutput: true)
        .do(onNext: { _ in
            self.navigationController?.popViewController(animated: true)
        })
        .subscribe(onNext: { client in
            debugPrint(client)
            self.viewModel.selectedClient.value = client
        }, onError: { error in
        debugPrint(error)
    }).disposed(by: disposeBag)

每当我查看第一个屏幕时都会触发事件(具有空值),然后,在从第二个屏幕选择客户端后,由于某种原因,没有触发任何事件。

首先,Variables 已弃用。

您应该使用不需要初始值的 PublishRelay,这样它就不会在您的第一个屏幕上订阅时触发。 中继的优点是它们不会出错或完成。

struct NewControlViewModel {
  let selectedClient = PublishRelay<Client>()
}

// NewControlTableViewController : viewDidLoad
choisirMandat.rx.tap.subscribe(onNext: { [unowned self] in
  let viewController = /* instantiate vc */

  // Make sure to use the same viewModel
  viewController.viewModel = self.viewModel

  self.present(viewController, animated: true)
}).disposed(by: disposeBag)

self.viewModel.selectedClient.debug().subscribe().disposed(by: self.disposeBag)

// ClientsTableViewController: viewDidLoad
tableView.rx.itemSelected.map { [unowned self] indexPath in
  return self.clients[indexPath.row]
}
.debug("client selected", trimOutput: true)
.do(onNext: { [unowned self] _ in
  self.navigationController?.popToRootViewController(animated: true)
})
.bind(to: self.viewModel.selectedClient)
.disposed(by: self.disposeBag)

附带说明一下,如果您想要功能齐全,客户端也应该来自 Rx 世界。 第二个旁注,您可以使用 debug() 运算符来打印事件。

bind(to:) 已添加到 RxSwift 4.1 中,因此请确保保持最新状态

我想我在这里发现了你的问题。你正在做的是

// NewControlTableViewController : viewDidLoad
viewModel.selectedClient.asObservable().subscribe { event in
    debugPrint(event)
}
 // ClientsTableViewController: viewDidLoad

tableView.rx.itemSelected.subscribe(onNext: { indexPath in
    let client = self.clients[indexPath.row]
    debugPrint(client)
    self.viewModel.selectedClient.value = client
    self.navigationController?.popToRootViewController(animated: true)

}).disposed(by: self.disposeBag)

您需要更改此行 "self.viewModel.selectedClient.value = client"。您需要使用以前的控制器实例或 NewControlTableViewController 实例,例如 self.newControlTableVC.selectedClient.value = client

我认为您正在尝试通过将值从 NewControlTableViewController 发送到 ClientsTableViewController 来使用视图模型。

此外,我做了与您相同的场景,并且在我的案例中效果很好。试试我的方案,如果它不能工作,一定是一些小问题。

希望对您有所帮助