Двухстороннее связывание в UITableView с использованием RxSwift

Я использую шаблон MVVM с RxSwift, RxCocoa, RxDataSources.

Я успешно заселил UITableView с массивом PaletteViewModel присутствует в ListViewModel используя RxDataSource но это один из способов связывания.

Я хочу достичь того, что я показал на картинке, т.е. я хочу связать UITextField от UITableViewCell к Observable который присутствует в некотором индексе в массиве в ListViewModel

я хочу делать 2 way binding с UITextField а также answer собственность PaletteViewModel, Если пользователь изменяет текст в textField, он должен изменить значение в свойстве answer, присутствующем в определенном индексе, и наоборот.

Как я могу достичь чего-то сложного, используя это, используя MVVM pattern с помощью ReactiveX рамки?

Что делать, если UITableViewCell некоторые IndexPath удаляется из памяти, так как он не виден, и значение наблюдаемого изменяется, это приведет к падению, так как UITextField при этом IndexPath вернет ноль?

1 ответ

UITextField является элементом ввода. Вам не нужно двухстороннее связывание с ним, потому что вы не должны динамически изменять его. Самое большее, что вы должны сделать, это инициализировать его, и вам не нужно связывание для этого.

Вы не упоминаете, какой будет конечный результат для этого ввода, поэтому ответ может отличаться от приведенного ниже. Это конкретное решение предполагает, что вам нужно отправить все ответы в виде группы на сервер или в базу данных. Может быть, когда кнопка нажата.

Ниже приведено много кода, но он компилируется как есть (с соответствующим импортом.) Вы можете подписаться на 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
}
Другие вопросы по тегам