我正在将MVVM模式与RxSwift,RxCocoa,RxDataSources一起使用。
我已经使用UITableView
成功地将PaletteViewModel
中存在的ListViewModel
数组填充到RxDataSource
中,但这是绑定的一种方式。
我想实现图片中显示的内容,即要将UITextField
中的UITableViewCell
绑定到Observable
,ListViewModel
存在于{{ 1}}
我想用2 way binding
的{{1}}和UITextField
属性来answer
。如果用户更改了textField中的文本,则应更改特定索引处的answer属性中的值,反之亦然。
如何使用ReactiveX
框架和PaletteViewModel
实现类似的复杂功能?
如果由于某些MVVM pattern
中的UITableViewCell
不可见而将其从内存中删除,并且可观察值的值被更改,将会导致崩溃,因为该{{1 }}会返回nil吗?
答案 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
}