loading...

MVVM and Coordinators is the Industry Standard Architecture

tom0pearson profile image Tom Pearson ・2 min read

I had a lot of phone calls as interview first stages when I was recently applying for iOS Developer jobs. At some point we would always start talking about what architectural patterns I use or am comfortable with. Each time I would say that I used MVVM with Coordinators and more often than not it seemed to be like magic words were spouting from my mouth - I was normally greeted with "oh, we use that too" and definitely got me an upper hand. This was in London but I wouldn't be surprised if this translates to most other countries/tech hubs as well.

So it seems that companies have widely adopted it rather than MVC/MVP/VIPER or anything else. My thoughts on why:

  • Closely related to MVC so easy for the whole team and newcomers to adopt
  • Allows reactive programming (RxSwift/Combine) to be easily slotted in as there are designated places for where the bindings should occur, and it seems like reactive programming will be the future
  • Provides guidelines for where to place certain pieces of code which better helps organise things than MVC but is more flexible and pragmatic than VIPER

What a coordinator looks like

I'm only going to describe coordinators because I think view models are covered widely elsewhere.

There isn't a set rule for what is or isn't a coordinator. I arrived at something like the following that suited most of my needs:

protocol Coordinator {
    var parentViewController: UIViewController { get }
    func start()
}

It's fairly simple but encapsulates everything a coordinator needs, something to present the new view controller that will be created, and a function to kick everything off.

Then we would create a new coordinator for each distinct workflow. For example, a logging in coordinator would look something like:

class LoginCoordinator: Coordinator {
    let parentViewController: UIViewController

    init(parentViewController: UIViewController) {
        self.parentViewController = parentViewController
    }

    func start() {
        let loginViewController = LoginViewController()
        parentViewController.present(loginViewController, animated: true)
    }
}

This is a simple example. Coordinators can be taken further if you want to restrict them to only be presented by other coordinators, so that they don't know about what ViewController is the root of which coordinator. In this case you would make a 'main' coordinator, and the coordinator protocol would have an array of child coordinators so they hold reference to the coordinators that they are presenting.

As the requirements of the workflow get more complex it's easy for the coordinator to get bloated. Also this example didn't use a view model but if we had used one the coordinator would be responsible for instantiating it and passing it into the view controller, so I'm sure you can appreciate things can get out of hand quickly.

Other skills in demand

  • TDD, but also just testing in general
  • Reactive programming - RxSwift/Combine

Further Reading

View Models

https://www.objc.io/books/app-architecture/ - a good book about different architectural patterns, MVVM + Coordinators is one of the ones covered

Posted on by:

Discussion

markdown guide