Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle navigation in iOS when using MVVM

Tags:

ios

mvvm

I've introduced ViewModels into my latest iOS app but I'm getting stuck at a few places. Was wondering if anyone here could send me in the right direction.

Basically, How/Where should navigation and error dialogs be handled.

For example, currently I have a registration process that consists of a RegistrationViewController and a RegistrationViewModel. When the register button is tapped in the UI a register method is called on the RegistrationViewModel. i.e. viewModel.register() from the controller

Question 1: How should navigation get handled? After the registration call to the web service successfully completes the app should navigate to one of a number of screens depending on some business logic. Currently I handle this in the ViewModel by calling into a navigation manager class. Navigator.goToSuccessScreen(). Is this acceptable? I get the feeling that this should rather be handled inside the controller rather than through the ViewModel, but then all the business logic to determine where to navigate to will be done in the view controller.

Question 2: How to show a error dialog? Lets say that the registration call above failed. And the UI needs to show a UIAlertView to the user. Would it be OK to call Navigator.displayError("some or other error message")? Or should, once again, be a way to route this back to the controller to show the message itself?

like image 791
Craigt Avatar asked Jan 08 '16 09:01

Craigt


People also ask

Can you explain MVVM and how it might be used on Apple's platforms?

MVVM (Model View ViewModel) is a design pattern, which has been widely used as more event-driven apps have started emerging. A few years back, if anyone built a product, it has probably been built using MVC (Model View Controller). In recent times, the MVC architecture has lost its place as the default design pattern.

Why MVVM is better than MVC iOS?

KEY DIFFERENCE In MVC, controller is the entry point to the Application, while in MVVM, the view is the entry point to the Application. MVC Model component can be tested separately from the user, while MVVM is easy for separate unit testing, and code is event-driven.

Does iOS use MVVM?

Whenever we start building a new application, this question always comes in our mind, which architecture pattern to choose for our new project. The most used architectural pattern in iOS is MVC. Most of the developers used the MVC pattern for their projects.


1 Answers

You can handle it by using route enum and make it observable in 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)

}

Observe route value from View(viewController) and present it when the value changes:

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

}
like image 160
Oleh Kudinov Avatar answered Sep 28 '22 08:09

Oleh Kudinov