I'm making an app which has a form in it. What I did is I use a UITableView to make the form with some sections in it. Each cell has a UITextField to get the user's input. Since I'm using RxSwift, I bind every textfield inside the cell to a BehaviorRelay to my ViewModel class. Unfortunately, it has a really strange behavior everytime the user inputs something to each cell. For example (as shown below) every time the user inputs some value to the first cell, after the user scrolls down, the last cell in the table view has the same value (Note that the user hasn't scroll the page yet, hence hasn't input any value to the last cell). The second example is when I input some value in the last 3 cells, the first 3 cell's values changed as well.
Here's how I manage to achieve this:
My custom cell class:
class FormTableViewCell: UITableViewCell {
@IBOutlet weak var titleLbl: UILabel!
@IBOutlet weak var valueTf: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
}
func configureCell(title: String, placeholder: String, keyboardType: UIKeyboardType? = .default) {
titleLbl.text = title
valueTf.placeholder = placeholder
valueTf.keyboardType = keyboardType ?? .default
}
func getValueAsDriver() -> Driver<String> {
valueTf.rx.text.orEmpty.asDriver()
}
}
How I configure each cell in tableView(_:cellForRowAt:) function in my UIViewController class (I have around 15 cells total in my app):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let formCell = tableView.dequeueReusableCell(withIdentifier: Config.FORM_TABLEVIEWCELL_ID) as! FormTableViewCell
if indexPath.section == 1 {
if indexPath.row == 0 {
formCell.configureCell(title: "Some title", placeholder: "Some placeholder", keyboardType: .decimalPad)
viewModel.bindValue(from: formCell.getValueAsDriver())
return formCell
} else if indexPath.row == 1 {
// Do pretty much the same thing as before
}
} else if indexPath.section == 2 {
// Do pretty much the same thing as before
} ...
return UITableViewCell()
}
How I bind the textfield value in my ViewModel class:
final class ViewModel {
private let _someValue = BehaviorRelay<String>(value: "")
func bindValue(from driver: Driver<String>) {
driver.distinctUntilChanged().drive(onNext: { [unowned self] value in
_someValue.accept(value)
}).disposed(by: disposeBag)
}
}
My question is how do keep the values for each textfield inside the cell when the user scrolls the tableview? Also if you have better approach please let me know. Thank you.
