根据 UITextField 中的值禁用按钮只能工作一次(RxSwift)
Posted
技术标签:
【中文标题】根据 UITextField 中的值禁用按钮只能工作一次(RxSwift)【英文标题】:Disabling a button based on value in a UITextField only works once (RxSwift) 【发布时间】:2019-05-31 13:13:06 【问题描述】:我正在尝试处理RxCocoa
,但遇到了一个与我尝试实现的一些动态 UI 行为相关的异常错误。
我有一个用于用户输入的UITextField
。将输入添加到 Realm 数据库的按钮绑定到 RxSwift
操作。这绝对没问题。
最初,我禁用了该按钮,直到 UITextField
中出现至少 1 个字符长度的文本 - 此代码工作正常。当我添加对 Action 的 executionObservables 参数的订阅时,我的代码中出现了该错误,该参数应在按下按钮后清除 UITextField。
预期行为:
无文本(初始状态)> 按钮已禁用 文本输入 > 按钮启用 已输入文本并按下按钮 > 已清除文本字段并禁用按钮实际行为:
无文本(初始状态)> 按钮已禁用 文本输入 > 按钮启用 已输入文本并按下按钮 > 已清除文本字段但按钮仍处于启用状态添加 debug() 表明绑定到 UITextField 禁用按钮已被释放,但我不知道为什么 UIViewController 及其关联的视图模型仍应在范围内。谁能指出我正确的方向?
代码sn-p:
func bindViewModel()
// populate table
viewModel.output.sectionedObservations
.drive(tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
// only allow enable button when there is text in the textfield
observationTextField.rx.text
.debug()
.map $0!.count > 0
.bind(to: addObservationButton.rx.isEnabled)
.disposed(by: disposeBag)
// clear textfield once Action triggered by button press has completed
viewModel.addObservation.executionObservables
.subscribe( [unowned self] _ in
self.observationTextField.rx.text.onNext("")
)
.disposed(by: disposeBag)
// add Observation to Realm using Action provided by the view model
addObservationButton.rx.tap
.withLatestFrom(observationTextField.rx.text.orEmpty)
.take(1)
.bind(to: viewModel.addObservation.inputs)
.disposed(by: disposeBag)
【问题讨论】:
除了你的问题 - 这个$0!.count > 0
是一个等待发生的崩溃。将其替换为安全操作,例如 . ($0?.count ?? 0) > 0
我知道,但感谢您强调。这是快速的实验性代码,肯定需要重构以处理可怕的可选代码!
如果我理解正确,您最终需要 viewModel 告诉 observationTextField
它的值应该是什么。我养成了为 viewModel 的每个输出创建 Driver
的习惯,然后将其绑定到您的文本字段。用它来替换你的viewModel.addObservation.executionObservables
我确实需要以编程方式修改 UITextField 的内容,但只是将其删除,所以我不会认为我需要来自视图模型的直接输入。使用 executionObservables 可确保 Action 已正确执行,并且由于修改是将 .text 属性设置为“”,我认为最好使用简单的方法
【参考方案1】:
我认为对于ControlProperty
trait 的行为方式存在一些误解。我们来看看具体的行为是Programmatic value changes won't be reported
订阅后这个 Observable observationTextField.rx.text
不会为两者发出事件:
self.observationTextField.rx.text.onNext("")
或
self.observationTextField.text = ""
我对您的代码有 2 条建议:
1) 手动完成工作:
viewModel.addObservation.executionObservables
.subscribe( [unowned self] _ in
self.observationTextField = ""
self.addObservationButton.isEnabled = false
)
.disposed(by: disposeBag)
2) 再添加一个 Observable 和订阅:
//a
viewModel.addObservation.executionObservables
.map _ in return ""
.bind(to: observationTextField.rx.text)
.disposed(by: disposeBag)
viewModel.addObservation.executionObservables
.map _ in return false
.bind(to: addObservationButton.rx.isEnabled)
.disposed(by: disposeBag)
//b
let executionObservables = viewModel.addObservation
.executionObservables
.share()
executionObservables
.map _ in return ""
.bind(to: observationTextField.rx.text)
.disposed(by: disposeBag)
executionObservables
.map _ in return false
.bind(to: addObservationButton.rx.isEnabled)
.disposed(by: disposeBag)
不确定Action
是如何实现的,为了防止工作完成两次,也许你必须共享资源。
【讨论】:
感谢指导谢尔盖。这成功了,现在我明白我做错了什么(希望再次犯这个错误!) 快速思考:在这种情况下,.do 不是首选 .subscribe(onNext:),因为我们正在执行 UI 副作用而不是更改流中的元素? UI 的手动更新比其他版本更紧凑(即使有额外的行),也同样富有表现力。我现在有了预期的行为。再次感谢 就我而言,我都可以接受:swift viewModel.addObservation.executionObservables .do(onNext: _ in self.observationTextField = "" self.addObservationButton.isEnabled = false ) .subscribe() .disposed(by: disposeBag)
和 swift viewModel.addObservation.executionObservables .subscribe( [unowned self] _ in self.observationTextField = "" self.addObservationButton.isEnabled = false ) .disposed(by: disposeBag)
我个人更喜欢订阅关闭中的代码。以上是关于根据 UITextField 中的值禁用按钮只能工作一次(RxSwift)的主要内容,如果未能解决你的问题,请参考以下文章
启用/禁用 UIButton 取决于 UITextField 中的文本长度