Как переместить логику для отображения UITableViewRowAction из метода делегата в модель представления (архитектура MVVM)

Я научился использовать RxSwift и RxDataSource для отделения бизнес-логики от View Controller (используя MVVM).

Предположим, я хочу создать табличное представление, как в почтовом приложении в iOS, когда пользователь проводит пальцем влево, появляются кнопка удаления и кнопка "Дополнительно".

В обычном MVC я должен реализовать метод делегата editActionsForRowAt.

public func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?

        var swipeActions = [UITableViewRowAction]()
        let removeAction = UITableViewRowAction(style: .destructive, title: "Delete") { [weak self] (action, indexPath) in
            guard let strongSelf = self else { return }
            strongSelf.deleteBankAccountTrigger.onNext(indexPath)
            tableView.deleteRows(at: [indexPath], with: .fade)
        }
        swipeActions.append(removeAction)

        if *cellIsNotDefault* {
            let makeDefaultAction = UITableViewRowAction(style: .default, title: "Make Default") { [weak self] (action, indexPath) in
                guard let strongSelf = self else { return }
                strongSelf.makeBankAccountDefaultTrigger.onNext(indexPath)
            }

            makeDefaultAction.backgroundColor = UIColor.lightGray
            swipeActions.append(makeDefaultAction)
        }

        return swipeActions

Я не знаю, как перенести логику cellIsNotDefault из делегата во ViewModel. Потому что я думаю, что логика для отображения/скрытия кнопки SwipeAction должна быть во ViewModel.

Любое предложение приветствуется.

Спасибо.

Обновлять:

Я пытался использовать RxDataSources, но до сих пор не знаю, как настроить пользовательское действие смахивания. Для действия удаления я могу использовать метод tableView.rx.itemDeleted, чтобы подписаться на него. Но если я хочу подписаться на пользовательское действие Swipe (например, мое действие Make Default). Как это сделать?


person Jefferson Setiawan    schedule 04.05.2018    source источник


Ответы (1)


Во-первых, viewModel должен содержать только те данные, которые отображаются конкретным представлением. Поэтому я не уверен, что viewModel должен содержать информацию о поведении вашего представления (в данном случае это означает, что ваша ячейка имеет какое-то действие). Возможно, я бы инкапсулировал эту логику в саму модель. Я предполагаю, что вы получаете от API что-то вроде isBankAccountDefault. Если вы не получаете этот атрибут прямо из API и вам нужна логика для его определения. Вы можете создать вычисляемое свойство внутри своей модели и поместить туда логику *cellIsNotDefault*.

Но если вы настаиваете на том, чтобы оно было во viewModel, вы можете создать свойство Bool isBankAccountDefault во viewModel. Затем вы поместите логику *cellIsNotDefault* в форматтер, то есть создадите эту модель просмотра, и установите значение isBankAccountDefault в соответствии с логикой *cellIsNotDefault*.

person Vojta    schedule 04.05.2018
comment
Спасибо за ответ @user3797599. Да, я согласен, что viewModel должна содержать только данные. Таким образом, оператор if else все еще находится в VC. Итак, я думаю, что мой вопрос неверен, я запутался, как передать значение из ViewModel в метод editActionsForRowAt. Я использую шаблон архитектуры Clean Architecture Rx Swift. И вывод привязан к viewDidLoad. Итак, как мне получить значение в editActionsForRowAt? - person Jefferson Setiawan; 07.05.2018
comment
Привет, Джеф, извини, что не вернулся к твоему вопросу. Я не так хорошо знаком с Rx Swift с чистой архитектурой, и в последнее время у меня не было времени, чтобы углубиться в него. Как вы решили свою проблему в итоге? - person Vojta; 21.05.2018
comment
В итоге я использовал PublishSubject для запуска ввода в модель представления. Когда пользователь выбирает эту опцию, я запускаю тему публикации и передаю модель. - person Jefferson Setiawan; 22.05.2018