Coordinator Tutorial for iOS: Getting Started
In this Coordinator tutorial you’ll convert an iOS app from using the MVC pattern to the Coordinator pattern and examine the pros and cons of Coordinators. By Andrew Kharchyshyn.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Coordinator Tutorial for iOS: Getting Started
25 mins
- Getting Started
- Current Implementation Problems
- Reusability Problems
- Coordinator Pattern
- Coordinator Protocol
- Apply the Coordinator Pattern
- Application Coordinator
- Kanji List Coordinator
- When to Create a Coordinator?
- Kanji Detail Coordinator
- Project Clean Up
- Extras: Coordinator Pattern with Storyboards
- Where To Go From Here?
Project Clean Up
There are still a few things you can change to make this even better.
First of all, in KanjiListViewController.swift and KanjiDetailViewController.swift remove the prepare(for:sender:)
method. You remove this code, because it will never get triggered with this architecture.
Still in KanjiListViewController.swift, remove this variable:
var word: String? {
didSet {
guard let word = word else {
return
}
kanjiList = KanjiStorage.sharedStorage.kanjiForWord(word)
title = word
}
}
This variable is also no longer used.
Now take a look at var shouldOpenDetailsOnCellSelection = true
in KanjiListViewController.swift. This flag was used to specify whether or not the UIViewController
will push KanjiDetailViewController
. Since this logic is now not in the KanjiListViewController
you need to make a small change.
Replace this:
var shouldOpenDetailsOnCellSelection = true
With this:
var cellAccessoryType = UITableViewCellAccessoryType.disclosureIndicator
And in tableView(_:cellForRowAt:)
change this:
cell.accessoryType = shouldOpenDetailsOnCellSelection ? .disclosureIndicator : .none
To this:
cell.accessoryType = cellAccessoryType
This property allows you to set the specific accessory type for cells. The problem is now that when a word is selected, you display the kanji list with a disclosure indicator.
To fix that, open KanjiDetailCoordinator.swift and look for kanjiDetailViewControllerDidSelectWord(_:)
. After you instantiate wordKanjiListViewController
, set its cell accessory type like this:
wordKanjiListViewController.cellAccessoryType = .none
wordKanjiListViewController
‘s cellAccessoryType
is set to .none
, because the logic for setting this property is handled in KanjiDetailCoordinator
. This saves wordKanjiListViewController
from knowing too much about the application.
Now for the last improvement. Open KanjiStorage.swift and delete this static variable:
static let sharedStorage = KanjiStorage()
Deleting this static variable is not enough; it’s still in use in KanjiListViewController.swift, where you set it as the default value for kanjiList
. Instead of giving kanjiList
a default value of the entire KanjiStorage
, display an empty list.
Change this line:
var kanjiList: [Kanji] = KanjiStorage.sharedStorage.allKanji()
To this:
var kanjiList: [Kanji] = []
Now you have a working app, with arguably cleaner and more flexible architecture, as well as no shared instances.
You can download the final project using the link at the top or bottom of this tutorial.
The Coordinator pattern might seem like an over-complication — and for a small project, it might be — but as soon as the application begins to grow, this pattern keeps the project straightforward and UIViewController
s independent. Coordinator
s are great, as they provide you with a clean architecture while requiring a relatively small number of changes to integrate with existing projects.
Extras: Coordinator Pattern with Storyboards
If you like storyboards, you can create a new file named Extensions.swift file and replace it with the following contents:
import UIKit
protocol StoryboardInstantiable: NSObjectProtocol {
associatedtype MyType // 1
static var defaultFileName: String { get } // 2
static func instantiateViewController(_ bundle: Bundle?) -> MyType // 3
}
extension StoryboardInstantiable where Self: UIViewController {
static var defaultFileName: String {
return NSStringFromClass(Self.self).components(separatedBy: ".").last!
}
static func instantiateViewController(_ bundle: Bundle? = nil) -> Self {
let fileName = defaultFileName
let sb = UIStoryboard(name: fileName, bundle: bundle)
return sb.instantiateInitialViewController() as! Self
}
}
Here’s what’s going on:
- You create an associated type to use inside of the protocol.
- Returns the filename, which is the name of a class without the module name.
- This is the main function; it searches for the Storyboard with the same name as
defaultFileName
, instantiates the firstUIViewController
from the Storyboard and returns it.
In the code above, you also created the StoryboardInstantiable
extension for UIViewController
. With it, you can just conform any UIViewController
to StoryboardInstantiable
, and you will be able to instantiate it.
To instantiate the UIViewController
, add this code to the bottom of the UIViewController
‘s file:
extension MyViewController: StoryboardInstantiable {
}
Inside the UIViewController
, add the following:
let viewController = MyViewController.instantiateViewController()
For example, if you wanted to use this code with KanjiDetailViewController
, it would look like the following:
extension KanjiDetailViewController: StoryboardInstantiable {
}
class KanjiDetailsCoordinator: Coordinator {
let viewController = KanjiDetailViewController.instantiateViewController()
}
With great power comes great responsibility (and limitations). To use this extension, you need to create a separate storyboard for each UIViewController
. The name of the storyboard must match the name of the UIViewController
‘s class. This UIViewController
must be set as the initial UIViewController
for this storyboard.
As a homework exercise, feel free to switch from .xib files to this approach, and please share your thoughts in the comments section below.
Where To Go From Here?
This concludes the Coordinator tutorial. One of the best advantages the Coordinator architectural pattern provides is the ability to easily change the application flow (show login screen, show tutorial screen, etc.) As an exercise in testing this, play around with the project and try creating and presenting a login screen instead of a list.
If you want to learn more about the Coordinator pattern, check out the videos below. They have some great explanations:
Coordinators presentation at NSSpain by Soroush Khanlou
Boundaries in Practice by Ayaka Nonaka at try! Swift
MVVM with Coordinators & RxSwift – Łukasz Mróz
The coordinator pattern is one of many useful design patterns you can use in iOS development. To learn more about other patterns, check out our video series on iOS design patterns. Also check out the video tutorials on our site for in-depth explanations on other iOS topics.
As always, if you have any questions, feel free to ask in the comment section below. :]