RxSwift:如何正确订阅变量变化
RxSwift: How to correctly subscribe to a variable change
我有两个屏幕:
NewControlTableViewController
: 包含一个用于从另一个视图中选择客户端的文本字段
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 来使用视图模型。
此外,我做了与您相同的场景,并且在我的案例中效果很好。试试我的方案,如果它不能工作,一定是一些小问题。
希望对您有所帮助
我有两个屏幕:
NewControlTableViewController
: 包含一个用于从另一个视图中选择客户端的文本字段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 来使用视图模型。
此外,我做了与您相同的场景,并且在我的案例中效果很好。试试我的方案,如果它不能工作,一定是一些小问题。
希望对您有所帮助