Coordinator iOS Jul 12 2019

I am using the coordinator pattern on my Counter App. These are the steps to implement the coordinator pattern.

1. Create a Coordinator protocol.

1
2
3
4
5
6
7
import UIKit

protocol Coordinator {
    var navigationController: UINavigationController { get set }

    func start()
}

2. Create a class that implements the Protocol

I normally use AppCoordinator.swift:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import UIKit

class AppCoordinator: Coordinator {
    var navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }
    func start() {
        let vc = DashboardViewController.instantiate()

        vc.coordinator = self
        navigationController.pushViewController(vc, animated: false)
    }
}

The start function is where it'll initialize our "root" controller. For this case, I'm initializing the DashboardViewController. I'm using a modified version of a Protocol by [Paul Hudson]https://www.hackingwithswift.com/about) called Storyboarded. Storyboarded simplifies the instantiation of specific ViewControllers (you should add an Identifier in the Attributes inspector on the Storyboard for your UIViewControllers for it to work).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Storyboarded.swift
import UIKit

protocol Storyboarded {
    static func instantiate(storyboard: String) -> Self
}

extension Storyboarded where Self: UIViewController {
    static func instantiate(storyboard storyboardName: String = "Main") -> Self {
        let fullName = NSStringFromClass(self)
        let className = fullName.components(separatedBy: ".")[1]
        let storyboard = UIStoryboard(name: storyboardName, bundle: Bundle.main)

        return storyboard.instantiateViewController(withIdentifier: className) as! Self
    }
}

All my Controllers implement the Storyboarded protocol and have an instance of coordinator. My controllers communicate with the coordinator about any event that changes the flow of the App. The coordinator is responsible for handling the workflow of the App, deciding whom to call and instantiate.

3. Initialize the Coordinator in AppDelegate

Now we have to tell the AppDelegate that when the application loads initialize the coordinator so, it can start "coordinating".

The AppDelegate.swift handles all the lifecycle of the app(going to background, initializing, being dismissed, etcetera). Inside didFinishLaunchingWithOptions , we initialize the coordinator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//AppDelegate.swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var coordinator: AppCoordinator?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let navController = UINavigationController()
        coordinator = AppCoordinator(navigationController: navController)
        coordinator?.start()

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = navController
        window?.makeKeyAndVisible()
        return true
    }
}

Usually, the App does all the window creation and presentation, but because we are taking control of the boot of the App, we have to do that too. That is why we create the window, assign the rootViewController and make it visible.

That's it.

References and resources


** If you want to check what else I'm currently doing, be sure to follow me on twitter @rderik or subscribe to the newsletter. If you want to send me a direct message, you can send it to derik@rderik.com.