Hello! It has been all-too-long since I last posted. Why? Because I have been learning, learning, grinding and grinding and it is now time to unleash all that I have been working on!

No really, today we’re going to start a series on the Coordinator design pattern as well as navigating to any part of the app using Dynamic Links. But ‘what are Dynamic Links’ you say? Dynamic Links are similar to Deep Links in that a message, email or text can be sent to a user, they tap it and it will automatically open your application. However Dynamic Links are Deep Links on steroids. Prescription ones of course, none of this illegal stuff.

Dynamic Links handle the scenario where the user doesn’t even have the app installed and when tapped the user will be taken to the App Store, prompted to install the app, then once installed the dynamic link will resume it’s original course to take the user to any part of your app. They are also pretty short links so rather than something like a huge URL that a user has to tap they can get sent something like ‘https://l1f3.1sG00D’ and it will take them right to your app.

I recently built this functionality into a very large-scale app which used the Coordinator design patter (which we’ll start by learning here). So, let’s begin…

Coordinator Design Pattern

The coordinator design pattern is an interesting one to work with. Every pattern has it’s strengths and weaknesses, but this one is without a doubt one of the main patterns to learn well and work with regularly. This is because it has a one-way flow that allows you to jump into lots of different parts of the app at anytime.

Let’s say you get a design flow come in, you build it using Storyboards and Segues and everything is fine. Then at the last minute, you have to move one view controller from one place to another… This is a very common issue in iOS development and it takes time to move things around. If you do the spadework with your Coordinator in the initial stages, later on you’ll be able to shift things any way you want with only tiny changes to an enum value! Totally worth it, plus you’ll learn stuff along the way.

So what is a coordinator? Well, it’s simply a class that handles flows throughout your app. Let’s start by defining it as a Protocol – make sure to include ‘ing’:


1
2
3
4
5
6
7
protocol Coordinating {
   
    func start()
   
    func goTo(route: Route)
   
}

Here, the only things we require to be a coordinator are two methods and a route type. The start method will be responsible for setting itself up with which view controller it is meant to show, and also is a descriptive place showing where everything kicks off. A route is a place to go and start the journey: a home route, or a settings route for example. The goTo(_:route) method is simply a way to navigate to where we want to go next in the application.

Think about British Queues: they are an unspoken ‘social protocol’ that we all ‘conform’ to and if someone doesn’t fit in the queue neatly, ALL HELL WILL BREAK LOOSE and there will be staring, shortness of breath and silent frowning amongst the innocent bystanders.

Next let’s imagine we’re making a simple tab bar app with 3 routes that the app can go down. You can think of a route as a journey you would normally follow visually with segues in Interface Builder.


1
2
3
4
5
enum Route {
    case Home
    case Feed
    case Settings
}

In this particular route we have the 3 journeys outlined, but your app could have many more and each route could have a child coordinator with more routes until we reach inception…

Coordinator Pattern


1
2
3
4
5
6
7
8
9
10
public final class AppCoordinator: Coordinating {
   
    func start() {
       
    }
   
    func goTo(route: Route) {
       
    }
}

Here we have created a new class AppCoordinator that is going to be responsible for navigating it’s way through our app for us. We’ve made it something that supports ‘Coordinating’ and so have had to add the methods to be able to support that. Next we’ll take a look at the initialiser:


1
2
3
4
5
6
7
    private var window: UIWindow
    private var navigationController: UINavigationController
   
    init(window: UIWindow, navigationController: UINavigationController) {
        self.window = window
        self.navigationController = navigationController
    }

We’re going to initialise this coordinator in the AppDelegate where we’ll inject a freshly-made navigation controller and a window. Why do we need a navigation controller though? Well, we’re going to take on some of that work that segues would usually do for us in that we’re going to push and pop our view controllers using it’s stack. We can inject anything we want here but we’re keeping it simple for now. We’ll talk about the window in a minute.

Let’s head over to the AppDelegate now and put our wonderful creation into use. Before we write any code though, what storyboards do for you under the hood is setup a few things and it’s good to know this stuff as it’s important here. First the app needs a Window initialised as well as a root view controller that is explicitly declared to appear. If this isn’t done we get a good old black screen!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
   
    var appCoordinator: AppCoordinator?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       
        // Setup our window
        let window = UIWindow(frame: UIScreen.main.bounds)
        // Initialise a navigation controller
        // Note: We won't use any of the provided initialisers for it as we don't want to set a root view controller yet
        let navController = UINavigationController()
        // Get our App Coordinator ready for action
        let appCoordinator = AppCoordinator(navigationController: navController)
       
        // Assign our creations to our local variables
        self.window = window
        self.appCoordinator = appCoordinator
       
        // Awake the Coordinator!!!
        appCoordinator.start()
       
        return true
    }
   
}

We’ve declared an appCoordinator variable and notice that optional window variable that was always there as well. Inside the didFinishLaunchingWithOptions method we’re simply getting everything setup and handing the responsibility for navigating over to our appCoordinator class.

Head back over to the AppCoordinator class and add the following:


1
private var rootViewController: UIViewController?

We’ll use this to set the root view controller of the window passed in from the App Delegate as well as keep a reference to it locally as we’ll want to change this.


1
private var rootViewController: UIViewController?

Finally add this to the AppCoordinator class:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    func start() {
        goTo(route: .Home)
    }
   
    func goTo(route: Route) {
        switch route {
        case .Home:
            // Just setup a standard view controller for now
            let homeViewController = UIViewController()
            self.rootViewController = homeViewController

            navigationController.show(homeViewController, sender: self)
           
        default:
            print("Set this up later")
        }
       
        refreshWindow()
    }
       
    // This is where the magic happens
    private func refreshWindow() {
        window.rootViewController = rootViewController
        window.makeKeyAndVisible()
    }

Here we’re going to call the ‘start’ method which, for now, will simply ‘goTo’ whichever route we want. We’ve presented a simply view controller for now but in the upcoming blogs we’ll also add custom view controllers and load them from Storyboards and Nibs just so you’re comfortable with both.

The magic happens in our refreshWindow method which sets the window’s rootViewController as the newly created one we just made and makes it key and visible. This is necessary to display everything correctly.

Wrapup

So that was a brief introduction to the Coordinator pattern. In the next few blogs we’re going to cover making our own view controllers, how to load them and present them and implement more flows into the app before finally adding in our Dynamic Links!