如何在使用MVVM时处理iOS中的导航

Cra*_*igt 5 mvvm ios

我已经将ViewModels引入了我最新的iOS应用程序,但是我在几个地方陷入困境.想知道这里是否有人能把我送到正确的方向.

基本上,应该如何/在哪里处理导航和错误对话框.

例如,目前我有一个注册过程,包括RegistrationViewController和RegistrationViewModel.当在UI中点击注册按钮时,在RegistrationViewModel上调用注册方法.即来自控制器的viewModel.register()

问题1:如何处理导航?注册调用Web服务成功完成后,应根据某些业务逻辑导航到多个屏幕之一.目前,我通过调用导航管理器类在ViewModel中处理此问题.Navigator.goToSuccessScreen().这可以接受吗?我觉得这应该在控制器内而不是通过ViewModel处理,但是后来确定导航到哪里的所有业务逻辑都将在视图控制器中完成.

问题2:如何显示错误对话框?可以说上面的注册调用失败了.UI需要向用户显示UIAlertView.可以调用Navigator.displayError("一些或其他错误消息")吗?或者,应该再一次将其路由回控制器以显示消息本身?

Ole*_*nov 1

您可以使用路由枚举来处理它并使其在 ViewModel 中可观察:

enum MoviesListViewModelRoute {
    case initial
    case showMovieDetail(title: String, overview: String, posterPlaceholderImage: Data?, posterPath: String?)
}

final class DefaultMoviesListViewModel: MoviesListViewModel {
        
    // MARK: - OUTPUT
    let route: Observable<MoviesListViewModelRoute> = Observable(.initial)
    ...
    func didSelect(item: MoviesListItemViewModel) {
        route.value = .showMovieDetail(title: item.title, 
                                       overview: item.overview, 
                                       posterPlaceholderImage: item.posterImage.value, 
                                       posterPath: item.posterPath)

}
Run Code Online (Sandbox Code Playgroud)

从 View(viewController) 观察路由值并在值变化时呈现它:

final class MoviesListViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        bind(to: viewModel)
        viewModel.viewDidLoad()
    }

    private func bind(to viewModel: MoviesListViewModel) {
        viewModel.route.observe(on: self) { [weak self] in 
            self?.handle($0) 
        }
    }

}

extension MoviesListViewController {
    func handle(_ route: MoviesListViewModelRoute) {
        switch route {
        case .initial: break
        case .showMovieDetail(let title, let overview, let posterPlaceholderImage, let posterPath):
            let vc = moviesListViewControllersFactory.makeMoviesDetailsViewController(title: title, 
                                                                                      overview: overview, 
                                                                                      posterPlaceholderImage: posterPlaceholderImage, 
                                                                                      posterPath: posterPath)
            navigationController?.pushViewController(vc, animated: true)
        }
    }

}
Run Code Online (Sandbox Code Playgroud)