ViewModel Входы и выходы для многосекционной таблицы в RxSwift - PullRequest
1 голос
/ 16 февраля 2020

Я реализую экран с многосекционным табличным представлением и кнопкой отправки.

1. TableView

a. Первый раздел - Stati c Данные (одна строка с вводом количества текста)

b. Второй раздел - данные Dynami c (несколько строк с банками и переключателями, связанными с каждым банком для выбора)

2. Кнопка «Отправить»

Кнопка активна, когда сумма выбор текста и банка переключателем сделан.

Вот код для Tableview DataSource, ViewModel и ViewController.

       enum PaymentDetailsSections {
            case amountDetailsSection(items: [RowItems])
            case vpaListSection(title: String,items: [RowItems])
        }

        enum RowItems {
            case linkedVPAs(info:String)
            case paymentInfo


        }

        extension PaymentDetailsSections: SectionModelType {
            typealias Item = RowItems
            var items: [RowItems] {
                switch  self {
                case .amountDetailsSection(items: let items):
                    return items.map { $0 }
                case .vpaListSection(title: _, items: let items):
                    return items.map { $0 }

                }
            }
             init(original: PaymentDetailsSections, items: [Item]) {
                switch original {
                case .amountDetailsSection(items: _):
                    self = .amountDetailsSection(items: items)
                case let .vpaListSection(title, _):
                    self = .vpaListSection(title: title, items: items)
                }
            }
        }
        extension PaymentDetailsSections {
            var title: String {
                switch self {
                case .vpaListSection(title: let title, items: _):
                    return title
                case .amountDetailsSection:
                    return  ""
                }
            }
        }


 class PaymentViewModel {

        Struct Input{
          let tableviewFirstSectionTextFieldInput: Observable<String>
          let tableviewSecondSectionSelectAnyBank: Observable<BankSelection>
          let submitButtonOutSideTableView: Observable<Void>
          }

        Struct Output{
          let results: Observable<Any>        
        }

      let sections:[PaymentDetailsSections]
      var likedAccountsRowItems = [RowItems]()


      init(_service:Service) {

               let vpas = service.linkedVPAs()

                 for  account  in vpas {
                        self.likedAccountsRowItems.append(RowItems.linkedVPAs(info:account))
                  }


                self.sections = [.amountDetailsSection(items: [.paymentInfo]), 
               .vpaListSection(title:"Transfer From", items:likedAccountsRowItems)]
        } 

  }      

        class PaymentController{

          override func viewDidLoad() {
                super.viewDidLoad()
                viewModel = PaymentViewModel()
                paymentListView.register(UINib(nibName:String(describing: SendMoneyAmountsDetailsCell.self), bundle:nil), forCellReuseIdentifier:String(describing: SendMoneyAmountsDetailsCell.self))
                paymentListView.register(UINib(nibName:String(describing: SendMoneyVPAListCell.self), bundle:nil), forCellReuseIdentifier:String(describing: SendMoneyVPAListCell.self))

                Observable.just(viewModel.sections)
                    .bind(to: paymentListView.rx.items(dataSource: self.datasource())).disposed(by: rx.disposeBag)
                paymentListView.rx.setDelegate(self).disposed(by: rx.disposeBag)
            }
             func datasource() -> RxTableViewSectionedReloadDataSource<PaymentDetailsSections> {
               return RxTableViewSectionedReloadDataSource<PaymentDetailsSections>(
                    configureCell: { dataSource, table, idxPath, _ in
                        switch dataSource[idxPath] {
                        case  .paymentInfo:
                        if let cell = table.dequeueReusableCell(withIdentifier:String(describing:SendMoneyAmountsDetailsCell.self), for: idxPath) as? SendMoneyAmountsDetailsCell {
                            return cell
                            }
                        case .linkedVPAs(_):
                            if let cell =  table.dequeueReusableCell(withIdentifier:String(describing: SendMoneyVPAListCell.self), for: idxPath) as? SendMoneyVPAListCell {
                                return cell
                            }

                        }
                        return UITableViewCell()
                },
                    titleForHeaderInSection: { dataSource, index in
                        let section = dataSource[index]
                        return section.title
                }
                )
                }

        }

Я не смог найти никакого решения, используя привязку в ViewModel для ввода из ViewController и сделать преобразование Ouput. Буду очень признателен за любую помощь, и спасибо всем, кто вносит свой вклад заранее!

1 Ответ

0 голосов
/ 16 февраля 2020

Subject s используются по двум причинам: когда вы конвертируете не-Rx-код в Rx и когда вам нужно привязать наблюдателя до того, как наблюдаемая станет существующей. Это пример последнего случая.

class PaymentViewModel {
    ...
    func output(for input: Input) -> Output {
        // put logic here.
    }
}

class PaymentController: UIViewController {
    ...
    func bind() {
        let input = PaymentViewModel.Input(
            tableviewFirstSectionTextFieldInput: textFieldInputSubject.asObservable(),
            tableviewSecondSectionSelectAnyBank: bankSelectionSubject.asObservable(),
            submitButtonOutSideTableView: submitButton.rx.tap.asObservable()
        )
        let output = viewModel.output(for: input)

        output.buttonEnabled
            .bind(to: submitButton.rx.isEnabled)
            .disposed(by: disposeBag)
    }

    let textFieldInputSubject = PublishSubject<String>()
    let bankSelectionSubject = PublishSubject<BankSelection>()
    ...
}

Функция bind() должна вызываться в viewDidLoad(). textFieldInputSubject должен прослушивать текстовое поле в первой строке, а bankSelectionSubject должен прослушивать кнопки в разделе сечения.

...