Coordinator Setup Changes
Tags: ios, swift
Published: 2021-12-13 14:36:49

---
title: Coordinator Setup Changes
published: true
description: Setting up an iOS project to use coordinators
tags: iOS, Swift
//cover_image: https://direct_url_to_image.jpg
---

It's been awhile since I set up a coordinator flow in a project. My previous project was well established and once the flow was set up to start the project, it was rarely modified. 

For those that are unfamiliar with the Coordinator pattern, there are many blog posts regarding use and set up. These are some of my favorites to look at because I always need a refresher when setting up a new project. 

* [Soroush Khanlou - The Coordinator](https://khanlou.com/2015/01/the-coordinator/)
* [Soroush Khanlou - Coordinator Redux](https://khanlou.com/2015/10/coordinators-redux/)
* [Paul Hudson - How to use the coordinator pattern in iOS apps](https://www.hackingwithswift.com/articles/71/how-to-use-the-coordinator-pattern-in-ios-apps)
* [Ian MacCallum - Coordinators, Routers, and Back Buttons](https://medium.com/hackernoon/coordinators-routers-and-back-buttons-c58b021b32a)
* [Ray Wenderlich - Coordinator Tutorial in iOS: Getting Started](https://www.raywenderlich.com/158-coordinator-tutorial-for-ios-getting-started)

So imagine my surprise when I decide to create a new sample project last week and couldn't find `var window: UIWindow?` anywhere in the AppDelegate. It's just not there. 

####The Old AppDelegate
![Old AppDelegate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0fxd5zf5xtvf0311hbf.png)

####The New AppDelegate
![New AppDelegate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h21xhcgyozrfbrlwed33.png)

As it turns out, some of the delegate methods associated with the AppDelegate have been migrated over to a new file that comes out of the box when setting up a new project, `SceneDelegate` when Apple released iOS 13. A wonderful overview of the differences in `AppDelegate` and `SceneDelegate` can be found here: [Understanding the iOS 13 Scene Delegate](https://www.donnywals.com/understanding-the-ios-13-scene-delegate/)

I strongly encourage reading the article, especially about changes to the `info.plist`, which I won't cover in this post.

####The SceneDelegate
![Scene Delegate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/phdl8kb8crcnggmwdqmw.png)

The `SceneDelegate` file now contains the window property.
`var window: UIWindow?`

Okay, no big deal, I'll set up my coordinator from here.

*Still doesn't work*

Well, looking at the developer documentation, the `AppDelegate` still conforms to `UIApplicationDelegate`, but the delegate methods have changed. It is still the file to use to register for Push Notifications, responding to those notifications, responding to events that target the app itself, but there is also a new area that allows you to configure the app scenes--specifically, connecting to and discarding SceneSessions.

The `SceneDelegate` file conforms to `UISceneWindowDelegate`, which itself conforms to `UISceneDelegate`. The `window` property is part of the `UIWindowSceneDelegate` and the main window associated with the scene. 

The associated functions in the `SceneDelegate` are protocol methods from `UISceneDelegate`. They handle what the app should do if the scene enters the foreground, goes to the background and handle any other life-cycle events occurring within a scene. 

But getting back to the `window: UIWindow` property, there is a new way to initialize this variable. In the past, initializing the window property in the `AppDelegate` was something like this: 

`self.window = UIWindow(frame: UIScreen.main.bounds)`

You can still set up your window this way. `UIScreen.main.bounds` still is available.  However, with the introduction to Scenes, Apple lets us know that there is a new, preferred way to initialize the `UIWindow`.

Inside of the delegate method, `func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)` sits this comment: 

>Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.

>If using a storyboard, the `window` property will automatically be initialized and attached to the scene.

>This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

So instead of using UIScreen to initialize the window frame, this is what is expected:

* Step One: safely unwrap the provided `scene: UIScene` in the delegate method and cast it as a `UIWindowScene`.
* Step Two: Initialize the `window` property using the unwrapped `UIWindowScene`.
* Step Three: set the `windowScene` property now found in a UIWindow with the unwrapped `windowScene` from step one. 

**Step three is vitally important, because if this step is missed, you'll just get a blank screen when running the app.** 

In code, this looks like the following:

```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
	guard let windowScene = (scene as? UIWindowScene) else { return }
	let uiWindow = UIWindow(frame: windowScene.coordinateSpace.bounds)
	self.window = uiWindow
	self.window?.windowScene = windowScene
}
```

Thus far, I haven't mentioned anything about the actual coordinator. I wanted to separate the two, because once the window initialization is set up, the coordinator piece is pretty straight forward.  

First, start with a protocol... :) 

```swift
protocol Coordinator {
    func start()
}
```

Next, create an application coordinator conforming to the protocol. (I'm using the [Ray Wenderlich blog post](https://www.raywenderlich.com/158-coordinator-tutorial-for-ios-getting-started) I linked above as my sample AppCoordinator)

```swift
class AppCoordinator: Coordinator {
    let window: UIWindow
    let rootViewController: UINavigationController

    init(_ window: UIWindow) {
	self.window = window
	rootViewController = UINavigationController()
		
	let mainVC = MainViewController()
	rootViewController.pushViewController(mainVC, animated: true)
	}
	
    func start() {
	window.rootViewController = rootViewController
	window.makeKeyAndVisible()
    }
}
```

After that, it's just a matter of modifying the previously mentioned delegate method in the `SceneDelegate`.

```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
	guard let windowScene = (scene as? UIWindowScene) else { return }
	let uiWindow = UIWindow(frame: windowScene.coordinateSpace.bounds)
	self.window = uiWindow
	self.window?.windowScene = windowScene
	
	let appCoordinator = AppCoordinator(uiWindow)
	self.appCoordinator = appCoordinator
	appCoordinator.start()
}
```

I chose to set up my app without using storyboards. Just note, to remove references to the storyboard, the main storyboard can be found in the `SceneConfiguration` in the `plist`.  Just deleting from the `Main Interface` in the App Target isn't enough.

![New location in plist](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9djeytv6vjgpxus9m4lq.png)

You can absolutely use coordinators with a storyboard (See Paul Hudson's article linked above) if you so choose.