RxSwift RxDataSources двухстороннее связывание
У меня есть некоторый код, основанный на примерах RxDataSources: https://github.com/RxSwiftCommunity/RxDataSources/blob/master/Example/Example3_TableViewEditing.swift
У меня есть источник данных UITableView, правильно привязанный к моим элементам таблицы и управляющий им, настройка для этого в контроллере представления следующая:
func setupMethodDataSources() {
let sections: [ComposeMethodSection] = [ComposeMethodSection(header: "", methodSteps: [])]
let initialState = MethodSectionedTableViewState(sections: sections)
let addInitialPlaceholderItems = Observable.of((), (), ())
let addCommand = Observable.of(addMethodButton.rx.tap.asObservable(), addInitialPlaceholderItems)
.merge()
.map(MethodTableViewEditingCommand.addPlaceholderItem)
let deleteCommand = methodTable.rx.itemDeleted.asObservable()
.map(MethodTableViewEditingCommand.deleteItem)
let movedCommand = methodTable.rx.itemMoved
.map(MethodTableViewEditingCommand.moveItem)
Observable.of(addCommand, deleteCommand, movedCommand)
.merge()
.scan(initialState) { (state: MethodSectionedTableViewState, command: MethodTableViewEditingCommand) -> MethodSectionedTableViewState in
return state.execute(command: command)
}
.startWith(initialState)
.map {
$0.sections
}
.share(replay: 1)
.bind(to: methodTable.rx.items(dataSource: methodStepsDataSource))
.disposed(by: disposeBag)
}
Источник данных methodStepsDataSource устанавливается из следующего статического метода:
static func methodStepsTableDataSource() -> RxTableViewSectionedAnimatedDataSource<ComposeMethodSection> {
return RxTableViewSectionedAnimatedDataSource(
configureCell: { dataSource, tableView, indexPath, element in
guard let cell = tableView.dequeueReusableCell(withIdentifier: ComposeMethodStepCell.reuseIdentifier,
for: indexPath) as? ComposeMethodStepCell else {
debugPrint("Failed to create 'ComposeMethodStepCell' cell!?")
return UITableViewCell()
}
cell.methodStepTextView.rx.text = element.description
return cell
},
canEditRowAtIndexPath: { _, _ in
return true
},
canMoveRowAtIndexPath: { _, _ in
return true
}
)
}
Ячейки таблицы довольно просты, они просто содержат одно текстовое представление, каждое из которых доступно для редактирования. Под таблицей у меня есть кнопка сохранения, которая при нажатии должна объединять последние из нескольких текстовых полей в любом месте экрана вместе с последним вводом текста из каждой ячейки таблицы. Чтобы сделать это, из контроллера представления я фиксирую событие нажатия кнопки внутри наблюдаемой и передаю его модели представления во время установки привязок. Код для этого выглядит следующим образом:
viewModel.setupBinds(title: titleTextView.rx.text.asObservable(),
summary: summaryTextView.rx.text.asObservable(),
description: descriptionTextField.rx.text.asObservable(),
/*tableSteps: ???*/
save: saveButton.rx.tap.asObservable())
В моделях представления 'setupBinds' я создаю одну наблюдаемую из всех входных наблюдаемых, слитых вместе, вот так (пока игнорируем 'tableSteps'):
let userInputs = Observable.combineLatest(title,
summary,
description,
/*tableSteps*/) { (title, summary, description/*, tableSteps*/) -> DataInputs in
return DataInputs(title: title, summary: summary, description: description/*, tableSteps: tableSteps*/)
}
Наконец, я наблюдаю за наблюдаемым нажатием кнопки и комбинирую последние из моих userInputs
наблюдаемый как это:
composeSaveAction = save
.withLatestFrom(userInputs)
.map { [weak self] userInputs in
// perform save logic
}
composeSaveAction.subscribe().disposed(by: disposeBag)
Все это прекрасно работает до того момента, когда я редактирую один из текстовых представлений таблицы. Первая проблема заключается в том, что изменение ввода текста не распространяется обратно на источник данных. Поэтому я исправил это, изменив строку:
cell.methodStepTextView.rx.text = element.description
в 'methodStepsTableDataSource', чтобы:cell.methodStepTextView.rx.textInput <-> element.description
(описание теперь Variable<String>
Теперь каждый раз, после внесения изменений в таблицу и нажатия кнопки сохранения, при проверке моих источников данных я мог видеть, что это изменение возвращается из текстового поля. Последняя оставшаяся проблема, однако, заключается в том, как фиксировать изменения источника данных. Всякий раз, когда я редактирую ячейку таблицы, мои 'user Inputs' должны перестраивать новый объект 'DataInputs' (как это происходит при редактировании других входных данных). Тем не менее, я не могу придумать способ наблюдать источники данных за изменениями или событиями таблицы, которые сработают, когда редактирование текстового представления завершится. В идеале это, например, еще один наблюдаемый "tableSteps" (который закомментирован), но точно ли это будет наблюдаться?
Итак, чтобы подвести итог, у меня есть коллекция элементов пользовательского ввода на экране, а затем табличное представление, которое управляется источником rxdatasource. Любые изменения элементов на экране фиксируются, и когда я нажимаю кнопку "Сохранить", я объединяю последние из всех этих элементов и выполняю некоторую логику постоянства. Тем не менее, я не могу придумать, как правильно фиксировать изменения в ячейках таблицы (предпочтительно, в виде массива текстовых строк ввода), несмотря на то, что дошло до того, чтобы вернуть их обратно в мой источник данных.
Извиняюсь за супер длинный пост! Совпадает ли то, что я пытаюсь достичь, с чем-то, что кто-то еще сделал, или у вас есть какие-либо предложения? Спасибо!