unknownProgrammer
unknownProgrammer

Reputation: 13

RxSwift: MVVM Update Struct on View Model and Trigger Table Update on View Controller

I am currently diving into RxSwift and I am trying to use it to update a TableView on a ViewController(.xib) with data that I get from a JSON and is encoded into a struct with Codable.

Here's my VM atm:

import Foundation
import RxCocoa
import RxSwift

protocol MenuViewModelProtocol {
    func viewDidLoad()
}

class MenuViewModel: MenuViewModelProtocol {

    private (set) var menu = MenuModel()
    private let menuIntermediary = MenuDataIntermediary()

    func viewDidLoad() {
        debugPrint("MenuViewModel.viewDidLoad: Async request for menu was made")
        requestAndSetMenuToIntermediary { (_ success) in
            switch success {
            case true:
                debugPrint("MenuViewModel.requestAndSetMenuToIntermediary: Did get Menu successfully")
                // print(self.menu) // -> menu is here
            case false:
                debugPrint("MenuViewModel.requestAndSetMenuToIntermediary: Did not get Menu successfully")
            }
        }
    }

    private func requestAndSetMenuToIntermediary(completion: @escaping (_ success: Bool) -> Void) {
        menuIntermediary.jsonDataToMenuConversion { [weak self] (success) in
            DispatchQueue.global().async {
                guard let strongSelf = self else {
                    debugPrint("MenuViewModel.requestMenuToIntermediary: couldn't create a strong self reference")
                    completion(false)
                    return
                }

                guard let menu = menu else {
                    debugPrint("MenuViewModel.requestMenuToIntermediary: couldn't unwrap menu data")
                    completion(false)
                    return
                }
                strongSelf.menu = menu

                // print(strongSelf.menu) // -> menu is here
                completion(true)
            }
        }
    }
}

The flow behing requestAndSetMenuToIntermediary is in short:

-> DataManager requests JSON from URL and returns a Data?

-> Intermediary Layer parses the JSON onto a Struct (with nested structs) using Codable and returns a Struct?

-> ViewModel gets the Struct? and unwraps it, being it ready for UI setup.

-> ??

My problem at '??' is to notify the VC that menu was updated in order to setup the TableView. Any suggestions? I've tried using PublishSubjects, BehaviorSubject combined with observables but I can't seem to make it work. I'm in doubt if it is syntax or something related to the background flow...

Thanks in advance! P.s - If more info is needed I can happily provide it, I was just trying to not make a very long post :p

Upvotes: 1

Views: 1465

Answers (1)

AIex H.
AIex H.

Reputation: 21

I do not find any code about data binding in your code. Normally, if you are using RxSwift, you should create a data sequence and bound to your view. For Table View or Collection View, we love using RxDataSource

  1. Create an Observable getting response from server
  2. Using map to Transform the data
  3. bind the data to your view

In you case, you should define a function to get menu model from server

private func getMenuModel() -> Obserable<MenuModel> {
   /* the code getting response from server and transform to menu model */
}

Declare an Observable

let menuModelObservable: Observable<MenuModel>

init() {
   menuModelObservable = getMenuModel()
}

Bind the data to your TableView

/* Your ViewController*/

override func viewDidLoad() {
    super.viewDidLoad()
    let viewModel = MenuViewModel()
    viewModel.menuModelObservable.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { index, model, cell in
      cell.textLabel?.text = model
    }.disposed(by: disposeBag)
}

Upvotes: 1

Related Questions