0

So far, I have been binding the post data from the existing view model. I need to do additional UI work on the table view cell using domain user data. Then, by creating a ViewModel for user data, do I need to have two ViewModels? Or do I have to deal with two Model(Post, UserData) in my existing ViewModel?

ViewController

class PostsViewController: UIViewController {
    let disposeBag = DisposeBag()

    var viewModel: PostsViewModel!

    override func viewDidLoad() {
        super.viewDidLoad()
        configureUI()
        connect()
    }
    func connect() {
        assert(viewModel != nil)
    
        let cellUpdate = PublishSubject<(PostItemViewModel.ID, Int)>()
    
        let viewWillAppear = rx.viewWillAppear
            .mapToVoid()
            .catchErrorJustComplete()
        let pull = timeLineTableView.refreshControl!.rx
            .controlEvent(.valueChanged)
            .asObservable()
        let reachedBottom = timeLineTableView.rx.reachedBottom().asObservable()
    
        let input = PostsViewModel.Input(fetchInitial: Observable.merge(viewWillAppear, pull), fetchNext: reachedBottom, updateTrigger: cellUpdate)
        let output = viewModel.transform(input: input)
    
        let dataSource =
        RxTableViewSectionedAnimatedDataSource<PostItemViewModelSection>(
            configureCell: { dataSource, tableView, indexPath, id in
                let cell =
                tableView.dequeueReusableCell(withIdentifier: PostTableViewCell.identifier, for: indexPath) as! PostTableViewCell
                cell.connect(postItem: output.posts.compactMap {
                    $0.first(where: { $0.id == id }) })
                .bind(to: cellUpdate)
                .disposed(by: cell.disposeBag)
                return cell
            },
            canEditRowAtIndexPath: { _, _ in true }
        )
    
        timeLineTableView.dataSource = nil
        timeLineTableView.delegate = nil
    
        viewModel.PostItemViewModelSections(postItem: output.posts)
            .drive(timeLineTableView.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    
    
        output.fetching
            .drive(timeLineTableView.refreshControl!.rx.isRefreshing)
            .disposed(by: disposeBag)
    }
}

Opt 1

class PostsViewController: UIViewController {
    let disposeBag = DisposeBag()

    var viewModel1: PostsViewModel!
    **var viewModel2: UserDataViewModel!**
    .....

Opt 2

class PostsViewController: UIViewController {
    let disposeBag = DisposeBag()

    var viewModel: PostsAndUserDataViewModel!
    .....
    let dataSource =
    RxTableViewSectionedAnimatedDataSource<PostItemViewModelSection>(
        configureCell: { dataSource, tableView, indexPath, id in
            let cell =
            tableView.dequeueReusableCell(withIdentifier: PostTableViewCell.identifier, for: indexPath) as! PostTableViewCell
            cell.connect(postItem: output.posts.compactMap {
                $0.first(where: { $0.id == id }) }, **userData: output.userData**)
            .bind(to: cellUpdate)
            .disposed(by: cell.disposeBag)
            return cell
        },
        canEditRowAtIndexPath: { _, _ in true }
    )
Seul
  • 47
  • 3

1 Answers1

0

A ViewModel's job is to provide state for a View. As such it is closely tied to the View it's providing state for. You seem to be tying your ViewModels to the Models instead.

A ViewModel, as the name suggests, models a View, a TableViewCell is a view. There is nothing wrong with giving the cell it's own ViewModel class and for each cell to have its own ViewModel instance. But having different ViewModels based on the model types feels wrong to me. That's more something a service would be for, not a ViewModel.

Daniel T.
  • 32,821
  • 6
  • 50
  • 72