
Break it down to Build it up – Typhoon Dependency Injection in Swift
Published on LinkedIn
Aside from the discomfort of that situation, I found myself curious about what drove this developer to such mad risk.
Therein I discovered the Typhoon dependency injection codebase.
Dependency injection is described by James Shore as a “25-dollar term for a 5-cent concept” (link) which I understand is common in php and javascript.
Objective-C was my first ‘real’ code language making dependency injection something new to my work flow.
Reported advantages of dependency injection include a better modularization of the code base and easier unit testing integration. A disadvantage is said to be the complexity this adds to a code base.
Let’s see for ourselves!
I’ve created a simple iOS application in Swift which presents a collection view supplied by mock JSON data here: GitHub.
This project is based on the Typhoon example project for Swift here, but simplified and adapted to my needs.
Build The Foundation
Start with an empty single-view iOS project.
We’re building this without storyboards which will make the version control history more person-readable.
Remove the Storyboard from the Project, and also from the info.plist file:
To keep with the Typhoon example code, I’ve renamed ‘ViewController’ to ‘RootViewController’, and have added window initialization code to the project’s AppDelegate.
RootViewController.swift:
AppDelegate.swift:
Pod Life
Cocoapods is required – installation instructions are here.
Open a Terminal window in OSX, navigate to your new project directory, and type ‘pod init’.
This will create a Podfile text document in your directory.
Edit the Podfile in Terminal via the ‘nano Podfile’ command, or use a code-oriented text editor:
Uncomment the use_frameworks! command, then add pod ‘Typhoon’:
Back in Terminal, type ‘pod install’.
This will create a Pod project in Xcode, import the Typhoon library, and create a workspace which now becomes the file to open your project with.
Your project directory now should resemble this:
In Terminal type ‘open your project name>.xcworkspace.
Your XCode project should look like this:
Bridge the Gap between Objective-C and Swift
In order for the Objective-C code base of Typhoon to work in Swift a bridging header is required.
Add a new header file to your Xcode project:
Name it after your project, for example, ‘TyphoonTest-bridging-header.
In project settings, add this file to the Build Settings in the format Project name>/Header name>:
In the header itself, add #import Typhoon/Typhoon.h> to bridge the code base.
Application, Assemble!
Your application is literally assembled by Typhoon depending on what you place in an Application Assembly file.
To simplify Typhoon’s integration, we can add this to the project info.plist:
Next create a new file in XCode called ApplicationAssembly.
I’ve placed it in an ‘Assemblies’ folder to keep things organized.
The Application Assembly syntax is meant to take advantage of custom initializers you write into your own classes.
You can ‘inject’ values from this Assembly into those view controllers, view classes and any custom classes derived from NSObject.
Likewise properties labeled ‘dynamic’ in other files can have their values injected from the ApplicationAssembly.
Root for the Root View
RootViewController.swift is a container for the actual content views.
A queue is provided to lock down the UI during changes.
RootViewController.swift:
Code to handle navigation is provided by the pushViewController:replaceRoot:function. Please note the function init(mainContentViewContainer:assembly, we’ll reference this soon in ApplicationAssembly.swift.
Rooting for the Delegate
To initialize the application without a storyboard, we inject the RootViewController into the AppDelegate.rootViewController variable.
AppDelegate.swift with rootViewController var:
ApplicationAssembly injecting the RootViewController class into the AppDelegate:
Lastly, ApplicationAssembly calls the RootViewController initializer.
ApplicationAssembly is injecting methods referencing the view controllers, it is not referencing them directly. Therefore rootViewController() is called:
You can see I’m referencing another new view controller that the user will see (blogListViewController). This new controller is developed similarly to rootViewController().
ApplicationAssembly (full):
BlogListViewController has a display UIView injected into it (blogListView).
RootViewController() is a container with the Blog List controller injected into it, and the Blog View is in turn injected into the Blog List controller.
Therefore we decouple the blog display view from the blog view controller, allowing us to reverse changes if desired.
Currently we use a collection view display in BlogListView().
If a table view is desired, all we need to do is write a blogTableView class, then replace BlogListView.self with BlogTableView.self in the ApplicationAssembly.
View changes become reversible and can be A/B tested without redoing work.
Mock that Data!
To speed up prototyping and testing, I’ve elected to cop data from Flicker’s API example here and place it into a JSON file in my project.
I also sequester data functions into a DataHandler class to read the JSON file and return a Swift data object.
DataHander.swift:
Now we create another assembly to inject JSON data into the Blog view.
DataAssembly.swift
A ‘DataClient’ class protocol and code is created to supply the application:
Changing the DataClientImpl code would allow us to switch from static JSON file data to an API without needing to update any of the view controllers.
Configure the Choir
Another neat trick is injecting properties from a plist into controllers.
Using Swift’s willSet{} function, we can have the UI update when data changes.
First let’s create a Configuration.plist and populate it with a font size and family:
Next add this Configuration to the ApplicationAssembly:
BlogListView.swift has fontPointSize and fontFamily vars.
Typhoon will inject this style information into these vars.
In turn BlogListView will use this font definition to build a font var, and style the UICollectionViewCells:
Typhoon injects the font size and family preferences from the ApplicationAssembly.swift:
It’s Alive!
We can see the result of our labour in the simulator:
With a simple change to the Configuration.plist, we can switch up the look of our prize collection view cells:
TL;DR
It’s the weekend, and I hope you’re out there crushing it or celebrating crushing it!
Using dependency injection via Typhoon in Swift, we can elect to break apart complex apps into a more manageable, testable, reversible code base.
At Xyris Interactive Design Inc, we’ve assembled a team of trusted talent I’ve known from five to almost 20 years.
If you have questions about your project and code base or need to move forward quickly, please feel free to write me at contact@xyriskenn.com.