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?
The Model-View-Controller (“MVC”) design pattern is useful, but it doesn’t scale well. As projects grow in size and complexity, this limitation becomes more apparent. In this Coordinator tutorial, you’ll try a different approach: Coordinators.
If you’re unfamiliar with the term, don’t worry! It’s a simple architecture that doesn’t require any third party frameworks, and it’s easy to adopt in your existing MVC projects.
By the end of this Coordinator tutorial, you’ll be able to decide which approach works best for you when building your apps.
Note: If you’re not familiar with MVC, check out Design Patterns in iOS.
Note: If you’re not familiar with MVC, check out Design Patterns in iOS.
Getting Started
To kick things off, start by downloading the materials for this tutorial (you can find a link at the top or bottom of this tutorial).
Note: The kanji data used in this Coordinator tutorial was provided by Kanji Alive Public API
Note: The kanji data used in this Coordinator tutorial was provided by Kanji Alive Public API
Kanji List is an app for learning Kanji (Chinese characters used in the Japanese language), and it’s currently using the MVC design pattern.
Let’s take a closer look at the functionality this app provides and how:
- KanjiListViewController.swift contains a list of the kanji.
- KanjiDetailViewController.swift contains information specific to the selected kanji, as well as the list of words that use that kanji.
- When a user selects a word from the list, the application pushes KanjiListViewController.swift and shows the list of kanji for that word.
There’s also Kanji.swift, which holds the data models; and KanjiStorage.swift, which is a shared instance. It’s used to store parsed kanji data.
Pretty straightforward, huh?
Current Implementation Problems
At this point, you may be thinking, “The app works. What’s the problem?”
That’s a great question! Let’s take a look.
Open Main.storyboard.
OK, this looks fishy. The app has a segue from KanjiListViewController
to KanjiDetailViewController
; and also from KanjiDetailViewController
to KanjiListViewController
.
The reason is because of the app’s business logic:
- First you push KanjiDetailViewController.swift.
- Then you push KanjiListViewController.swift.
If you think the problem is in the segues, you’re partially right.
Segues bind two UIViewController
s together, making those UIViewController
s very difficult to reuse.
Reusability Problems
Open KanjiListViewController.swift. Notice it has a property named kanjiList
:
var kanjiList: [Kanji] = KanjiStorage.sharedStorage.allKanji() {
didSet {
kanjiListTableView?.reloadData()
}
}
kanjiList
is a datasource for KanjiListViewController
, and its default is to display all of the kanji from the shared KanjiStorage
.
There’s also a property named word
. This property is a hack that allows you to reuse KanjiListViewController
for both the first and third screens:
var word: String? {
didSet {
guard let word = word else {
return
}
kanjiList = KanjiStorage.sharedStorage.kanjiForWord(word)
title = word
}
}
By setting word
, you change both kanjiList
and the title that’s displayed in the UINavigationBar
:
Consider for a moment. KanjiListViewController
knows the following things:
- There might be a word selected.
- The word has kanji.
- If there is no word selected, then the app should show all of the kanji in
kanjiList
. -
KanjiListViewController
knows that it’s in aUINavigationController
, and that it should change the title if a word is selected.
That seems pretty complicated for something as simple as a UIViewController
displaying a list of items.
One way to fix this unnecessary complexity is to pass the list of kanji to the KanjiListViewController
; but who should pass it?
You can create a UINavigationController
subclass and inject the data into its child, but does this code belong in the UINavigationController
‘s subclass? Shouldn’t UINavigationController
be a simple container for UIViewController
s?
Another problematic place is prepare(for:sender:)
, which is located in KanjiDetailViewController.swift:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let listViewController = segue.destination as? KanjiListViewController else {
return
}
listViewController.shouldOpenDetailsOnCellSelection = false
listViewController.word = sender as? String
}
This code means that KanjiDetailViewController
knows about the next UIViewController
, which in this case is KanjiListViewController
.
If you were to reuse KanjiDetailViewController
, the code would quickly get out of hand, because this method would need to grow into a giant switch statement so it knew which view controller to push next. This is why the logic shouldn’t be inside of another view controller — it creates a strong connection between view controllers, making them have more responsibility than they should.
Coordinator Pattern
The Coordinator pattern is a potential solution to all of the problems mentioned above. This pattern was first introduced to the iOS community by Soroush Khanlou (@khanlou) in his blog and during his presentation at the NSSpain conference.
The idea of the Coordinator pattern is to create a separate entity — a Coordinator
— which is responsible for the application’s flow. The Coordinator
encapsulates a part of the application. The Coordinator
knows nothing of its parent Coordinator
, but it can start its child Coordinator
s.
Coordinator
s create, present and dismiss UIViewController
s while keeping the UIViewController
s separate and independent. Similar to how UIViewController
s manage UIView
s, Coordinator
s manage UIViewController
s.
Coordinator Protocol
It’s time to dive into some coding!
First, create a Coordinator
protocol. From the main menu, click File\New\File…. Then, select the iOS\Source\Swift File and name the new file Coordinator.swift. When you’re done, click Next and then Create.
Now, replace its contents with the following:
protocol Coordinator {
func start()
}
Believe it or not, that’s it! All the Coordinator
protocol needs is one start()
function!
Apply the Coordinator Pattern
Because you want the Coordinator
to handle the application’s flow, you need to provide a way, within the code, to create UIViewController
s. For this Coordinator tutorial, you’ll use .xib files instead of storyboards. With these files, you’ll be able to create UIViewController
s by calling the following:
UIViewController(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
Note: The Coordinator pattern doesn’t require that you use .xib files. You can create UIViewController
s in code, and you can also instantiate them from storyboards, which you’ll see at the end of the Coordinator tutorial.
Note: The Coordinator pattern doesn’t require that you use .xib files. You can create UIViewController
s in code, and you can also instantiate them from storyboards, which you’ll see at the end of the Coordinator tutorial.
Add these .xib files to the project target by dragging and dropping them into the Project navigator in Xcode. Open KanjiDetailViewController.xib and KanjiDetailViewController.swift in the Assistant editor and make sure that all of the outlet connections are properly set. Do the same for KanjiListViewController.xib and KanjiListViewController.swift.
Note: In the File inspector, make sure that both .xib files are added to the target.
You need to replace Main.storyboard as the application starting point.
Right-click Main.storyboard, choose Delete then click Move to Trash.
Click on the KanjiList project in the File navigator and open the KanjiList target > General, and delete Main as the Main interface:
Now you need to create your own starting point.