If you're familiar with Cocoacasts, then you should know that I'm a big proponent of dependency injection. I tend to discourage developers from using the singleton pattern if the goal is creating an object that is easily accessible from anywhere in the project. That's not what the singleton pattern is about. You can learn more about the singleton pattern by reading Are Singletons Bad.
I won't cover dependency injection and the singleton pattern in detail in this episode. You can find plenty of information on Cocoacasts about these patterns. If you're unfamiliar with dependency injection, then I encourage you to stop here and read Nuts and Bolts of Dependency Injection in Swift first.
Dependency injection has many benefits and it's very easy to adopt using the coordinator pattern. As a matter of fact, the Photos project already takes advantage of dependency injection. Let me show you what I mean.
Types of Dependency Injection
In every discussion about dependency injection, I bring up James Shore's definition of dependency injection.
Dependency injection means giving an object its instance variables. Really. That's it. - James Shore
There are three types of dependency injection, (1) initializer injection, (2) property injection, and (3) method injection. The types of dependency injection we explore in this episode are initializer injection and property injection.
Initializer Injection
We're currently not using initializer injection in the Photos project. Let me show you a straightforward example of the coordinator pattern and initializer injection. The starter project of this episode is identical to the finished project of the previous episode. Remember from the previous episode that the Photos project defines three TermsViewController subclasses. Let's take the TermsViewControllerXIB class as an example.
What I'm about to show you isn't mind boggling, but it illustrates the concept of initializer injection. Open TermsViewControllerXIB.swift and define a private, constant property, termsOfService, of type String. We declare the property privately, which means that no other object but the view controller can access it. The let keyword ensures that the property is immutable. That's another key benefit of initializer injection.
import UIKit
class TermsViewControllerXIB: TermsViewController {
// MARK: - Static Properties
static var nibName: String {
return String(describing: self)
}
// MARK: - Properties
private let termsOfService: String
...
}
Create an outlet for the label that displays the terms of service to the user. We set the text property of the label in a didSet property observer. I use property observers quite often to configure user interface elements. It keeps the configuration of the user interface element close to its declaration.
import UIKit
class TermsViewControllerXIB: TermsViewController {
// MARK: - Static Properties
static var nibName: String {
return String(describing: self)
}
// MARK: - Properties
private let termsOfService: String
// MARK: -
@IBOutlet var termsOfServiceLabel: UILabel! {
didSet {
termsOfServiceLabel.text = termsOfService
}
}
...
}
Open TermsViewControllerXIB.xib and select the File's Owner in the document outline on the left. Open the Connections Inspector on the right and connect the outlet we defined a moment ago to the UILabel that displays the terms of service.

Revisit TermsViewControllerXIB.swift and create an initializer that accepts one argument, termsOfService, of type String. We assign the string that is passed to the initializer to the termsOfService property. The string is set or injected into the TermsViewControllerXIB instance during initialization hence the term initializer injection.
After setting the termsOfService property, we invoke the init(nibName:bundle:) initializer of the TermsViewController class, the parent or superclass of the TermsViewControllerXIB class. That should look familiar.
import UIKit
class TermsViewControllerXIB: TermsViewController {
// MARK: - Static Properties
static var nibName: String {
return String(describing: self)
}
// MARK: - Properties
private let termsOfService: String
// MARK: -
@IBOutlet var termsOfServiceLabel: UILabel! {
didSet {
termsOfServiceLabel.text = termsOfService
}
}
// MARK: - Initialization
init(termsOfService: String) {
// Set Terms of Service
self.termsOfService = termsOfService
super.init(nibName: TermsViewControllerXIB.nibName, bundle: .main)
}
}
Let's assume that the application fetches the terms of service from a remote API. We don't want to put the view controller in charge of making a request to the remote API. Instead, another object fetches the terms of service and injects them into the terms view controller using initializer injection.
But it seems we have a problem. The compiler throws an error. The TermsViewController subclass is required to implement every required initializer of its superclass and that includes the init(coder:) initializer. Click the Fix button to fix the error.
// MARK: - Initialization
init(termsOfService: String) {
// Set Terms of Service
self.termsOfService = termsOfService
super.init(nibName: TermsViewControllerXIB.nibName, bundle: .main)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
I won't cover the details of why we are required to implement the init(coder:) initializer in this episode. Class inheritance and initialization are fairly complex topics in Swift. Let's stay focused on dependency injection and put the initializer we implemented to use.
Open TermsCoordinator.swift and navigate to the showTerms() method. Instead of invoking the init(nibName:bundle:) initializer of the TermsViewControllerXIB class, we invoke the init(termsOfService:) initializer, passing in the terms of service.
// MARK: - Helper Methods
private func showTerms() {
// Initialize Terms View Controller
// let termsViewController = TermsViewControllerXIB(nibName: TermsViewControllerXIB.nibName, bundle: .main)
let termsViewController = TermsViewControllerXIB(termsOfService: "These are the terms of service.")
// Install Handlers
termsViewController.didCancel = { [weak self] in
self?.finish()
}
// Present Terms View Controller
presentingViewController.present(termsViewController, animated: true)
}
Build and run the application to see the result. Tap one of the Buy buttons of the photos view controller, sign in, and tap the Terms of Service button of the buy view controller. The example is a bit contrived, but I hope it's clear that any object can be passed to the view controller during initialization using initializer injection.
Property Injection
Even though initializer injection has a number of key benefits over property and method injection, property injection is what you most commonly use when working with view controllers. Instead of passing a dependency during initialization, a dependency is injected into the view controller by setting a property. Property injection is the type of dependency injection we're already using in the Photos project.
Open AppCoordinator.swift and navigate to the showPhoto(_:) method. The application coordinator creates an instance of the PhotoViewController class by invoking the instantiate() method. It uses property injection to inject the photo object into the view controller.
private func showPhoto(_ photo: Photo) {
// Initialize Photo View Controller
let photoViewController = PhotoViewController.instantiate()
// Configure Photo View Controller
photoViewController.photo = photo
// Install Handlers
photoViewController.didBuyPhoto = { [weak self] (photo) in
self?.buyPhoto(photo, purchaseFlowType: .horizontal)
}
// Push Photo View Controller Onto Navigation Stack
navigationController.pushViewController(photoViewController, animated: true)
}
Property injection may sound complex, but, as you can see in the showPhoto(:_) method, it's nothing more than setting one or more properties of the view controller. The view controller doesn't know or care where the Photo object comes from and that's the gist of dependency injection.
There's an important difference between initializer injection and property injection. By injecting a dependency during initialization, the property that is used to keep a reference to the dependency can be declared privately and as a constant. This means that the property is immutable. It can only be set once. This isn't possible if you choose for property injection. The property that is used to keep a reference to the dependency cannot be declared privately and it should be declared as a variable. This implies that the dependency can be accessed and replaced at any time. In other words, the dependency isn't immutable.
Poor Man's Dependency Injection
The Photos project doesn't use a library or framework to manage and inject dependencies. This is sometimes referred to as pure dependency injection or poor man's dependency injection. This works fine for smaller projects.
If you're working on a larger or more complex project, then you may want to opt for a dependency injection library or framework. That's up to you to decide. Both solutions work fine with the coordinator pattern.
MVVM-C
We revisit dependency injection later in this series when we discuss the Model-View-ViewModel pattern. The most common question I receive about the Model-View-ViewModel pattern is "Which object should be responsible for creating the view model of a view controller?" I answer that question later in this series. I can already tell you that the Model-View-ViewModel pattern works very well with the coordinator pattern. That's why it's often referred to as MVVM-C or the Model-View-ViewModel-Coordinator pattern.
What's Next?
I encourage you to read more about dependency injection if you're not familiar with this pattern. I use dependency injection in every project I work on without exception. It allows me to write loosely coupled code and it helps me reduce the need for singletons.