MVVMとCoordinatorで画面遷移


概要

M(Model)-V(View)-VM(ViewModel)って画面遷移はViewの仕事なのかなと思って調べたところCoordinatorパターンというものがあることをしったので、MVVMにどうにかして組み込んで見ようとしたらできた(なんとか)ので記事にします。

説明

ますどういった仕組みで遷移させるか説明します。
ViewModelViewControllerのプライベートなプロパティにします。
そしてViewModelBuilderというViewModelを初期化するための変数を作ります。
そしてCoordinatorから画面遷移する時に

Coordinator.swift
let vc = ViewController()
vc.viewModelBuilder = {
    let viewModel = ViewModel(input: $0)
    return viewModel
}

という感じでコードを書きます。
ここでViewModelにボタンタップを検知するようにしておけば遷移はできますよね。

Coordinator.swift
viewModel.input.buttonTap.subscribe(onNext: {
    // 遷移処理
}).disposed(by: disposeBag)

こんな感じです。
ここで重要なのが今回は単純な画面遷移機能というところです。
もしこれがログイン画面のCoordinatorだとしたらログイン処理はここですべきではないですよね。
ログイン処理はViewModelでして、画面遷移はcoordinatorに任せたいです。
それはどうやって実現するのかというと、

ViewModel
var tapEventSubject = PublishSubject<()>()

input.buttonTapped.drive(onNext: {
    // クロージャを引数にもつログイン処理 {
        tapEventSubject.onNext(())
    }
}).disposed(by: disposeBag)

このようにログイン処理完了した後にクロージャでonNextを流し、coordinatorで

Coordinator.swift
let vc = ViewController()
vc.viewModelBuilder = {
    let viewModel = ViewModel(input: $0)
    viewModel.tapEventSubject.subscribe(onNext: {
        // 遷移処理
    }).disposed(by: disposeBag)
    return viewModel
}

というように参照すれば役割は果たせてるのかなと思います。

まとめ

今回はそれぞれの役割というものにだけ着目していたので
subjectはprivateにしとけよとか、もっとこうすればsubject使わなくてもいけるといった意見があるとございます。

改善案、質問などございましたら是非コメントしていただけると嬉しいです。
Coordinatorの利用が今回初めてだったので、もっと勉強して理解を深めて行きたいです。