Modular iOS
Reusing code with Swift frameworks
Copy and pasting code sucks, even more when you find a bug and have to fix all the apps using it. But is there a way to avoid it?
Yes there is! Apple provides a tool called frameworks to ease code sharing. Furthermore it also provides us with a mechanism to group related code (modularisation) and restrict access to code (encapsulation).
In this article we will be covering what a framework is and why to use them. I will follow with a step by step guide on how to create and build a framework, and finally how to consume the framework in an app. The code within the framework will be exclusively written in Swift for this article.
What is a framework?
A framework is a structured directory that can contain shared code and shared resources such images, nibs (compiled form of xibs and storyboards) and other assets. You can think of it as package to deliver your code and/or other reusable assets to make your code work.
Why use frameworks?
We have covered the main reasons to use frameworks. Yet another good reason is to ease integration with your organisation’s services.
For example, Paypal provides frameworks to help apps process credit cards transactions. Onfido provides a framework to carry out remote identity verification.
Frameworks can save your customers integration efforts with your services. For customers its time and money saved. The faster customers can consume your services the earlier you can start making money 💰.
Furthermore time and effort can be key factors for prospects when selecting providers. In fact Stripe, valued over $9.2bn, started out of integration frustration with payment processors.
How to build a framework
In this section we will run you through the process of creating and building a framework. The framework will contain a simple login screen.
In the next steps we will:
- Create a project using Cocoa Touch Framework template
- Add a view controller using XIB’s
- Insert view into our view controller to allow the user to sign in
- Wire up the views in the XIB to the LoginViewController class
- Loading of view controller programmatically
- Accessing view controller outside the framework
Feel free to skip any part or all if you are already familiar with these.
1. Create project
Let’s begin by creating a framework in Xcode by selecting File > New > Project… from the menu bar.
Continue by selecting the iOS Cocoa Touch Framework project template and click Next.
Finally name your framework, you can name it whatever you want. I am going with the name MyFramework. Also make sure that the selected language is Swift. Once you name it click Next and select where you like to store the project and finally click on Create.
You should now have a project with an empty framework. Let’s proceed and add a screen to our project that can be consumed by multiple apps.
2. Add view controller
Let’s continue by adding an empty XIB file where we will design our login screen using interface builder. Select File > New > File… from the menu bar and then select Cocoa Touch Class.
Name your class LoginViewController as subclass of UIViewController. Check the option Also create XIB file. From the language dropdown select Swift.
Using the Cocoa Touch Class template, Xcode will add an XIB and a Swift file with the name we specified. It will create the necessary link from the XIB to the view controller for us.
3. Adding views to our view controller
At this point our LoginViewController
XIB will be completely empty. Let’s add labels and text fields for email and password to allow a user to authenticate.
Click on the object library. When the search bar appears, search for label and then drag and drop the label onto the empty canvas.
Repeat the three steps for textfield.
Align the views as you wish and then copy and paste them so you have two labels and two text fields, one for email and one for password. Edit the labels with meaningful texts such as Email and Password. Finally add a button to allow the user to carry out the signing in action.
At this point we have everything we need to get the user signed in. Don’t worry too much about the layout and appearance of the views, that is beyond the scope of this article.
4. Wiring up the views to the view controller
In this step we’ll simply have to create a link from the email and password text field views in the XIB onto our view controller to fetch the text from. Additionally we will also be wanting to hook up the tap action on the Sign In button to a function on our view controller where we’ll do the signing in.
First open LoginViewController.xib and then the assistant editor which is the two intersecting loops icons on the top right hand corner of the Xcode UI.
Then select one by one the text fields and hold Control key and drag and drop the view onto the view controller. This will open a popup that will allow us to configure the connection between the XIB and the view controller. For now set the connection for text field to Outlet, the name to something relevant for each text field such as emailTextField, the type UITextField and from the last from down select weak. Repeat the steps for password text field.
Now drag and drop the sign in button, but in this case select Action for connection, name it signIn and select Touch Up Inside from the dropdown below the type dropdown. This is a little bit different, we are hooking up an action on a view rather than the view itself, in this we are specifying a function to react to the tap on the Sign In button.
For now we will print the username and password to console. Add the following line within the sign in function:
print("username \(emailTextField.text) password \(passwordTextField.text)")
We now have everything we need to get the user signed in. We won’t be covering authentication here and the code is to demonstrate an app accessing framework code and resources. We will be loading our view controller programatically but before we can do that our view controller has to know which XIB to load.
5. Loading the view controller programatically
Our XIB contains declarations of our views and how these are structured, configured and linked. The XIB has a notion of who to link with and how, however our view controller has no idea about our XIB, so when we instantiate our view controller as it is right now the views and links on our view controller won’t be created. We have to tell our view controller where to read its views from when instantiated. Add the following custom init function for our view controller which reads from our xib:
init() { super.init(nibName: "LoginViewController", bundle: Bundle(for: LoginViewController.self))}required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented")}
We will be calling the init()
function to instatitate our view controller. UIViewController
already contains an init
function which allows us to specify which XIB to read (name of the file) and where to find this XIB file; init(nibName:_, bundle:_)
. For the XIB location we are specifying that it will located in the same bundle asLoginViewController
class.
Let’s ignore the required init?
function as we won’t be using it but we are obliged to specify it in our view controller when we want a custom initializer.
By now we should be able to load our view controller programmatically but only within the code inside the framework. We want to initialise ourview controller from the app consuming the framework.
6. Accessing the view controller outside the framework
Swift has access controls in place which restrict which parts of the code are accessible from other code. When we don’t specify any access control to our functions and variables, Swift defaults these to internal access such that init()
is equivalent to internal init()
. In this case all code contained within our framework can access the init
function but not outside. To allow access to our code from outside our framework we have to prepend our init
function with public
access control declaration such that our init
function should look like:
public init() { super.init(nibName: "LoginViewController", bundle: Bundle(for: LoginViewController.self))}
But that’s not all it takes to make our init
function public
ly available. Our init
function lives within a class which also has no access control specified, thus being internal
. If our class isn’t accessible so will be our public init
method that lives within it. To remedy that we also have to prepend public
access control to our class. You might have to add public
to any function after the keyword override
but
public class LoginViewController: UIViewController { ... }
Now we can initialise our view controller from an app consuming the framework.
And that’s all we need to do to showcase how to share code and resources in a standardised framework format to other developers.
Consuming the framework
In this section we will be consuming the framework that we built on the previous section through an app we will now create. If you have skipped the previous section you can find the framework project source code here.
We will:
- Create a new project with an iOS app target
- Add a login button to our view controller
- Present framework login screen on button tap
1. Create new project
Let’s create a new project for our framework consumer app. Select File > New > Project… from the menu bar.
Under the iOS tab search and select Single View App and then click Next.
Type in MyApp for Product Name. Select Swift as the Language. Click Next.
When prompted where to save the new project, for convenience save it under the same directory of our framework project.
2. Add a login button
Let’s add button onto our view controller which was automatically created for us as part of the Single View App template. Open Main.storyboard
and drag and drop a button onto the empty canvas. Just like we did for the sign in button earlier in the framework project, open the assistant editor and drag and drop the button from the storyboard onto the ViewController
class. Configure the connection type to Action, name it login and select Touch Up Inside from the dropdown below the type dropdown. You should have the following empty function in your ViewController
class:
@IBAction func login(_ sender: Any) {}
From within the login function we want to present the login screen from our framework.
3. Present framework login screen on button tap
At this point we have created a new project, added a button to the automatically created view controller and hooked up the button tap to a function within ViewController
class. We want to present the login screen from the framework we created earlier when the user taps the login button. But before we can do that we first have to link the framework to our app. There are various ways we can have access to the framework but for this article we will be using Xcode workspace to do so. In a workspace you add multiple projects and link them together like they are under single project.
To create a workspace select File > New > Workspace… and name it MyApp. Save it in the same directory as your app and framework project.
The workspace will be empty at first so lets add both projects to our workspace. Select File > Add Files to “MyApp”… from the menu bar and add MyApp.xcodeproj and MyFramework.xcodeproj which are located under directories named MyApp and MyFramework respectively. Make sure none of these projects are open on other XCode windows otherwise they won’t show their contents.
Next select MyApp project file (the blue document icon in the project navigator which is under the first tab on the right hand side pane). Then on project setting window under the General tab and under the Embedded binaries section click on the + button. A new window will appear with all the options you have within the workspace. Select MyFramework.framework and click Add.
Now that we have added the framework the app lets present login screen when the user taps on the login button. Open ViewController.swift
and add import MyFramework
under import UIKit
, this will allow us to access the framework code from our file. Next add the following line of code to the login function within the ViewController
class:
present(LoginViewController(), animated: true, completion: nil)
This line will present the login screen from the framework when the user taps on login button in the app.
And that’s all! Now you can run the app and see it in action yourself!
Summary
By now you should know:
- what a framework is
- why you should use them
- how to build and consume them
- h̶o̶w̶ ̶t̶o̶ ̶m̶a̶k̶e̶ ̶e̶a̶s̶y̶ ̶m̶o̶n̶e̶y̶
Next steps
Consuming frameworks using Xcode workspaces is hard. Is there an easier way to consume frameworks?
You will find answer to that question in the next article. Stay tuned! Follow me on Twitter or Medium.