使用RxSwift在UITableView中进行2种方式绑定

时间:2019-02-09 07:43:55

标签: uitableview rx-swift 2-way-object-databinding rx-cocoa rxdatasources

我正在将MVVM模式与RxSwiftRxCocoaRxDataSources一起使用。

enter image description here

我已经使用UITableView成功地将PaletteViewModel中存在的ListViewModel数组填充到RxDataSource中,但这是绑定的一种方式。

我想实现图片中显示的内容,即要将UITextField中的UITableViewCell绑定到ObservableListViewModel存在于{{ 1}}

我想用2 way binding的{​​{1}}和UITextField属性来answer。如果用户更改了textField中的文本,则应更改特定索引处的answer属性中的值,反之亦然。

如何使用ReactiveX框架和PaletteViewModel实现类似的复杂功能?

如果由于某些MVVM pattern中的UITableViewCell不可见而将其从内存中删除,并且可观察值的值被更改,将会导致崩溃,因为该{{1 }}会返回nil吗?

1 个答案:

答案 0 :(得分:1)

UITextField是一个 input 元素。您不需要双向绑定,因为您不应该动态更改它。您最应该做的就是将其初始化,并且不需要绑定。

您没有提及此输入的最终输出是什么,因此答案可能与以下内容有所不同。此特定解决方案假定您需要将所有答案作为一个组推送到服务器或数据库。也许当点击按钮时。

下面有很多代码,但是可以按原样进行编译(带有正确的导入)。您可以订阅ListViewModel.answers来查看所有收集的答案。

class ViewController: UIViewController {

    @IBOutlet weak var myTableView: UITableView!
    let bag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let answersSubject = PublishSubject<(PaletteID, String)>()
        let viewModel = ListViewModel(answersIn: answersSubject.asObservable())

        viewModel.paletteViewModels
            .bind(to: myTableView.rx.items(cellIdentifier: "Cell", cellType: MyCell.self)) { index, element, cell in
                cell.answerTextField.text = element.initialAnswer
                cell.answerTextField.rx.text.orEmpty
                    .map { (element.id, $0) }
                    .bind(to: answersSubject)
                    .disposed(by: cell.bag)
            }
            .disposed(by: bag)
    }
}

class MyCell: UITableViewCell {
    @IBOutlet weak var answerTextField: UITextField!
    let bag = DisposeBag()
}

struct ListViewModel {
    let paletteViewModels: Observable<[PaletteViewModel]>
    let answers: Observable<[PaletteID: String]>

    init(answersIn: Observable<(PaletteID, String)>) {
        paletteViewModels = Observable.just([])
        answers = answersIn
            .scan(into: [PaletteID: String]()) { current, new in
                current[new.0] = new.1
            }
    }
}

struct PaletteViewModel {
    let id: PaletteID
    let initialAnswer: String
}

struct PaletteID: RawRepresentable, Hashable {
    let rawValue: String
}