RxSwift:如何正确订阅变量更改
我有两个屏幕:RxSwift:如何正确订阅变量更改,swift,rx-swift,Swift,Rx Swift,我有两个屏幕: NewControlTableViewController:包含一个文本字段,用于从其他视图中选择客户端 ClientsTableViewController:第二个视图包含可选择的客户端列表 这两个屏幕共享一个viewmodel 这是我的代码: import RxSwift import RxCocoa struct NewControlViewModel { var selectedClient = Variable<Client>(Client()
NewControlTableViewController
:包含一个文本字段,用于从其他视图中选择客户端ClientsTableViewController
:第二个视图包含可选择的客户端列表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)
导入RxSwift
进口RxCocoa
结构NewControlViewModel{
var selectedClient=变量(Client())
//其他东西
}
//NewControlTableViewController:viewDidLoad
viewModel.selectedClient.asObservable().subscribe{event in
调试打印(事件)
}
//ClientsTableViewController:viewDidLoad
/*tableView.rx.itemSelected.subscribe(onNext:{indepath in
让client=self.clients[indexPath.row]
调试打印(客户端)
self.viewModel.selectedClient.value=client
self.navigationController?.popToRootViewController(动画:true)
}).处置(由:self.disposeBag)*/
//新代码
tableView.rx
.modelSelected(Client.self)
.debug(“已选择客户端”,输出:true)
.do(onNext:{uu}in
self.navigationController?.popViewController(动画:true)
})
.subscribe(onNext:{client in
调试打印(客户端)
self.viewModel.selectedClient.value=client
},onError:{中有错误
调试打印(错误)
}).处置(由:处置人)
每当我查看第一个屏幕时,就会触发事件(带有空值),然后,在从第二个屏幕选择客户端后,出于某种原因,不会触发任何事件。首先,不推荐使用
变量
您应该使用不需要初始值的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)
struct NewControlViewModel{
让selectedClient=PublishRelay()
}
//NewControlTableViewController:viewDidLoad
choisirMandat.rx.tap.subscribe(onNext:{[unowned self]在
让viewController=/*实例化vc*/
//确保使用相同的viewModel
viewController.viewModel=self.viewModel
self.present(viewController,动画:true)
}).处置(由:处置人)
self.viewModel.selectedClient.debug().subscribe().disposed(由:self.disposeBag)
//ClientsTableViewController:viewDidLoad
tableView.rx.itemSelected.map{[unowned self]indexath在
返回self.clients[indexPath.row]
}
.debug(“已选择客户端”,输出:true)
.do(onNext:{[unowned self]uuu in
self.navigationController?.popToRootViewController(动画:true)
})
.bind(到:self.viewModel.selectedClient)
.处置(由: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来使用viewmodel
此外,我做了与您相同的场景,在我的案例中效果非常好。只要试试我的方案,如果它不能工作,一定有一些小问题
我希望这可能会有所帮助您是否忘记在NewControlTableViewController
中使用.disposed(by:)
?该dispose
方法用于在控制器解除分配后处理流。在这种情况下不重要!:)你确定你没有在过程中的某个地方变异selectedClient
?做一个让
检查一下。你能解释一下吗。我没有收到你的信question@TimofeySolonin我需要将selectedClient
设置为可变的,以便在用户选择客户端时,我可以稍后对其进行更改。这是错误的。试着制作一个类似于OP文章中描述的场景,它会按照预期工作。当struct被传递时,它将复制所有包含的引用类型。@timofeysolon嘿,你说得对。我做了同样的场景,它对我有效。我的问题是使用同一viewModel
对象的两个不同实例。而不是这样做,我将把viewModel对象传递给ClientsViewController
的viewModel对象,因此现在两者共享同一个实例!