Двухстороннее связывание в UITableView с использованием RxSwift - PullRequest
0 голосов
/ 09 февраля 2019

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

enter image description here

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

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

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

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

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

1 Ответ

0 голосов
/ 10 февраля 2019

A 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...