Search code examples
iosswiftmvvmrx-swiftrxdatasources

How to move logic to show UITableViewRowAction from delegate method to View Model (MVVM Architecture)


I'm learn to use RxSwift and RxDataSource to separate business logic from View Controller (using MVVM).

Suppose I want to create table view like in the Mail App in iOS, when user swipe left, there are delete button and More button.

In the normal MVC, I have to implement delegate method 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

I don't know how to move logic cellIsNotDefault from the delegate to ViewModel. Because I think the logic to show/hide SwipeAction button should be in ViewModel.

Any suggestion is welcome.

Thank you.

Update:

I tried to use RxDataSources, but still no clue for custom swipe action. For delete action, I can use tableView.rx.itemDeleted method to subscribe to it. But if I want to subscribe to the custom Swipe action (like my Make Default action). How to do that?


Solution

  • First of all, viewModel should contain just data that are displayed by particular view. So I'm not sure if viewModel should contain information about behaviour of your view ( in this case it means that your cell have some action ). Maybe I would encapsulate this logic to the model itself. I guess that you get from API something like isBankAccountDefault. If you don't get this attribute straight from API and you need some logic to determine it. You can create computed property inside your model and put there * cellIsNotDefault * logic.

    But if you insist on having it in viewModel, you can create Bool property isBankAccountDefault in viewModel. Then you will put logic * cellIsNotDefault * to formatter, that is creating that viewModel and set isBankAccountDefault value accordingly to * cellIsNotDefault * logic.