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

时间:2016-01-08 09:04:22

标签: ios mvvm

我已将ViewModels引入我最新的iOS应用程序中,但我遇到了几个问题。想知道这里是否有人能把我送到正确的方向。

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

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

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

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

1 个答案:

答案 0 :(得分: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)

}

从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)
        }
    }

}