I'm trying to get to grips with RxCocoa
and have experienced an unusual bug relating to some dynamic UI behaviour I'm trying to implement.
I have a UITextField
that's used for user input. The button which adds the input to a Realm database is bound to an RxSwift
Action. This works absolutely fine.
Initially, I disabled the button until there was text of at least 1 character in length in the UITextField
- the code of this works fine. The bug in my code arose when I then added a subscription to the Action's executionObservables parameter that should clear the UITextField after the button is pressed.
Expected behaviour:
- No text (initial state) > button disabled
- Text entered > button enabled
- Text entered and button pressed > text field cleared and button disabled
Actual behaviour:
- No text (initial state) > button disabled
- Text entered > button enabled
- Text entered and button pressed > text field cleared BUT button remains enabled
Adding debug() indicates that the binding to the UITextField that disables the button is disposed but I can't figure out why as the UIViewController and its associated view model should still be in scope. Can anyone point me in the right direction?
Code snippet:
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)
}