Preventing Bloated View Controllers with Coordinators in iOS
Overstuffed View Controllers: a problem that is universally despised by iOS developers the world over. Who hasn’t had their eyes glaze over while staring down debugging a 3000 line VC? View Controllers can control so much information, and Apple seems to have very few opinions on where specific logic should go. They give us the decision making power. How can we prevent against this annoying problem and modularize our apps better? Model–View–View Model (MVVM) can certainly help with this, but ultimately leaves routing to View Controllers, which doesn’t make the most sense. This is where a Coordinator comes in.
What is a coordinator?
A Coordinator is an object that handles routing of view controllers. Why would we want to separate routing to its own object? In its purest form, the View Controller should only be passing data from the Model to the View. It can update the model based on what’s going on in the view, it can show the model in the view, but it should not be touching other parts of the application. A VC shouldn’t care what VC comes after it, or what the hierarchy of Views looks like. A Coordinator can coordinate all of that information. It can take care of creating VCs based on certain events.
Example
Let’s say we want to check if a user is authenticated. Previously, we might check in the App Delegate or in a Home View Controller, which decides whether to show a log in modal on top of the current view. Instead, we can initialize the Coordinator that will make these routing decisions.
In App Delegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
appRouter.route(to: login);
}
In AppRouter.swift
Class AppRouter {
public enum Route {
case login
}
func route(to newRoute: Route) {
case .login:
if loggedIn
//initialize home VC
else
//initialize login VC
break
case .home:
//initialize home VC
break
...
}
}
As you can see, the AppRouter class can become very powerful and abstract away control of navigation from View Controllers. The AppRouter can also initialize child coordinators if necessary to break up routing even further. This allows code to flow in a more logical, modular fashion.
Why should you use App Coordinators?
- View Controllers have an isolated scope, allowing them to do the job of acting as an intermediary between the model and the view more efficiently.
- You can easily reuse View Controllers by initializing them as needed in the Coordinator.
- They allow for app logic to be more easily understood and debugged.
- You are now in control of the View Controller life cycle.
- They’re incredibly simple to implement.
Coordinators can help take your code to the next level by organizing routing code, cleaning up View Controllers, and simplifying routing logic. If you are not using them already, you should give them a try!