Cocoa Scientist

Luna

Tracking the Moon Phase with iOS and Swift

Overview

This article examines how to write a basic iOS app in Swift that uses data from the Aeris Weather API to display phases of the Moon. The app is built using the MVVM design pattern and uses a single view controller with a table view inside.

The app is centered around two design goals: first, to create a lean but solid code base, and second, to use only Foundation and UIKit APIs while avoiding third party code. While these aren’t necessary real-world production goals, they do help to solidify the core concepts of iOS and Cocoa.

While examining the app, we’ll look at the established patterns in Cocoa but also explore new design idioms made possible by Swift.

This is not a Hello World app tutorial per say, but several introductory topics are covered in depth. It is assumed that you have a basic working knowledge of Swift and have read the official eBook from Apple (skimming or mostly reading is ok too). If you’re completely new to Cocoa and Cocoa Touch, it might be helpful to read the introductory guide from Apple, Start Developing iOS Apps Today.

With that said, we will cover several concepts in detail and provide enough information to build a robust app from the ground up. The content is mostly focused on iOS, but no platform is an island unto itself, so we’ll also touch on JSON data and web services.

The completed project is available on GitHub, updated in January 2016 for Swift 2.1.

Architecture

Let’s begin with a high level statement about the app we’re trying to build. By starting out with a clear idea in mind, the stage will be set for later discussion about architecture and design. Summarizing the app in one sentence makes its purpose clear and succinct.

The app should display the moon phase and calendar for the current location.

Simple enough. How we go about building, designing and creating it is another story. We need to make decisions about what the app looks like and how the data is received. Let’s assume up front that the Moon phase data is received from a web service, a remote API. While the phase could be calculated using mathematics, we’re less interested in astronomy and more interested in building an app that’s representative of a real world problem set.

When building an app that’s largely driven by remote data, it’s really all about the API.

An Application Programming Interface or API is a set of exposed functionality that’s part of a larger library, component, or service. The entity exposing an API handles some special functionality– this could be anything; serving images, posting updates, drawing graphics. It’s through the API that other interested parties can leverage the functionality exposed.

When researching for an API to design our app around, we’ll need to look at the endpoints and the returned data, and then imagine what model objects would be built from the responses. From a design point of view, most of the discussion starts with the API. Resource representations and endpoints will dictate many decisions made at the model and network level.

The API documentation should provide details about each endpoint along with accepted parameters. A sample response for different queries is also typically shown.

The Aeris API documentation provides just the sort of information we’re looking for. The /sunmoon endpoint accepts a location and returns moon phase information. We’ll dive more into the API later and discuss the JSON in detail, but feel free to peruse the documentation– the response JSON is fairly readable.

Now that we’ve chosen the API, we now have a way to find the moon phase from a latitude/longitude pair. Next we can begin focusing on the architecture and start imagining what app components we might need.

Speaking in broad terms, the app must find the user’s location, determine the moon phase and calendar for that location, and display the results within the app. When the location changes, a new dataset should be retrieved and displayed. Any errors should be shown.

So we need a mechanism for tracking location and another for returning information about the Moon. We also need a view controller to display the results. The view controller can manage some subviews and display the moon phase with a slick UI.

The architecture diagram below illustrates how information will flow through our app. Not all of the parts need to make sense right now. We’ll discuss each component in depth as we build the app.

First the location update comes in from the location tracker. Then the model issues two requests to the remote API using the updated location. When the responses are returned, the model now has a valid representation of the current moon and phases. The view controller and data source are notified by the model of the new data. View-models are then constructed and the information is reflected in the UI.

Design and Mockups

Now that we’ve looked at the underlying architecture, let’s begin thinking about designing some UI mockups. At this point, pen and paper is your best friend. Just start drawing.

At a high level, our app will have a table view and a table header view. The cells within the table view will display a Moon phase calendar and the table view header will display current Moon phase. The table header will take up the full screen. Scrolling the table will reveal the calendar cells below the header.

Mockup of the App

We have an architecture in mind and a vision for our user experience. Next we’ll look at some important concepts in software development and some patterns that are central to the Cocoa framework.

Architectural Patterns

An architectural pattern is a high level description of the fundamental structure of a software system. It defines application components, assigns responsibility, and creates pathways for information flow.

There are many patterns used in software development and they are found at different levels. Using patterns helps to promote abstraction by defining reusable solutions that can be applied in different contexts. They also create a separation of concerns by siloing different responsibilities in isolated components.

Think of a pattern as a rough sketch instead of a blueprint– accurate, but with limited scope and lacking details.

We’ll discuss the Model-View-* family of patterns, which includes MVC and MVVM. Each pattern assigns specific roles and responsibilities to different components and describes the communication channels between them.

Model-View-Controller

Model-View-Controller (MVC) is an architectural pattern for designing apps and structuring the components within. The pattern assigns one of three roles to each object, placing it within the Model, View, or Controller layer.

MVC has long been the pattern to use when developing iOS apps. It is heavily championed by Apple and central to the concepts within the Cocoa Frameworks.

A model object represents some piece of data specific to the context of the app. For instance, a model object might represent the text of an email, an item on a todo list, or a music track belonging to a playlist. Model objects are typically persisted to disk or contain a mechanism for serializing data. Ideally, a model object should have no reference to objects within a layer– the objects should be pure and only represent application data.

A view object represents a visible user interface element inside an app. The purpose of the view is to display data from the model. A view object is capable of drawing its content and presenting itself on screen. View objects are able to dynamically adjust layout for different screen sizes. When a user interacts with your app, they do so using the view. A view object shouldn’t contain any direct references to the Model. Instead, the view should become aware of model changes through communications with the controller.

A controller object sits between the model and view and passes data and user actions back and forth. A controller passes data up to the view to display on screen and interprets user input as data events. On iOS controllers are often subclasses of UIViewController.

Model-View-ViewModel

Model-View-ViewModel (MVVM) is a variant of MVC which adds a new view-model role into the mix. It has gained more popularity as an alternative to MVCs.

A view-model exposes properties for the view to bind to and performs validation logic on behalf of the view. The view-model interacts with the model through method calls and wraps model data in a format the view can use. For example, the view-model might call methods on the model to set a date field, while on the other side exposing a nicely formatted date property for the view.

Data Binding or binding is an important aspect to making all of this work. Binding works by establishing a link between two object values so both are kept in sync. This is usually accomplished through a language or framework construct. On macOS, Cocoa bindings are available to facilitate data binding. This technology isn’t available on iOS, but similar binding techniques can be accomplished using Key-Value Observing (KVO).

Design Patterns

A design pattern is a reusable solution to a common problem that can be applied again and again, in different contexts. It’s a set of abstractions and formalized best practices that can be used as a template for solving many different problem types. When used properly, design patterns can speed up development without reinventing the wheel.

Cocoa makes heavy use of design patterns throughout the framework and they play an important role in understanding how the various moving pieces fit together. Let’s briefly look at some of the more important design patterns and concepts. Many of these and more are covered in Cocoa Core Competencies.

Delegation

Under the delegate pattern, one object relies on another object to handle certain responsibilities on behalf of it. This allows an object’s behavior to be customized by passing off some responsibility to another object. When interacting with Cocoa, it’s common that you create objects that act as a delegate and handle different functionality on behalf of the framework.

As an example of delegation, think of company with a CEO and several employees close by. The office cannot function if the CEO does everything, so they must delegate responsibilities to other employees. A job can be passed off with responsibility given to an employee to finish it. When complete, the employee reports back to the CEO with the completed job.

This concept is powerful because the CEO doesn’t need specialized skills to complete the job. That’s why the employee was hired. How the employee did the job is not of any interest to the CEO. The CEO can safely assume the task will by performed, because responsibility was delegated to someone else.

Protocol

Protocols are an alternative to subclassing that utilize an interface to allow unrelated classes to communicate. The interface is a list of functions that a class must implement in order to conform to a protocol. You can think of the protocol as an agreement or loose contract.

Delegates and protocols are closely related. Typically an object expecting a delegate will specify a protocol that the delegate must conform to. This way, the delegating object has a guarantee that the object delegated to will perform a function, because the delegate conforms to a protocol.

Taking the office analogy further, imagine there is an Accountant protocol. The protocol specifies that given some set of spreadsheets a yearly report will be generated. The CEO has several Accountants on staff, and they all conform to the Accountant protocol. That is, they are all capable of generating reports from spreadsheets. When delegated to, each Accountant will generate his or her own report, on their own, in private. One might use a hand calculator, one might use a slide rule– it doesn’t matter. They all conform to the Accountant protocol and they will all generate a report when asked to.

Taken together, when an object wishes to delegate some tasks or set of tasks, it declares a protocol that any delegate must conform to. It specifies the functions an object must implement in order to assume the delegated responsibilities. But it also allows a nice disconnect between the two objects, where the only shared knowledge is the protocol. This is often referred to as loose coupling.

Singleton

The Singleton pattern dictates only one instance of a particular class is instantiated. Singletons are not created directly but instead a reference is retrieved using a shared mechanism. All iOS apps have at least one singleton, which is the AppDelegate. Several other Cocoa classes are used as singletons including NSFileManager, NSNotificationCenter, UIApplicationDelegate.

Singletons are often considered bad practice and can be easily be misused. However, they are central to Cocoa, where it’s common to interact with framework objects through a singleton.

Observer

In the Observer or Notification pattern, one object maintains a list of independent objects that are notified about any state changes that occur in the originating objects. The passing of a notification occurs through a method or function callback.

This pattern is popular in event communication where the occurrence of one event needs to propagate to some set of interested parties. It’s also central to the MVC family of design patterns, as a means of loose coupling between two roles.

Hollywood Principle

The Hollywood Principle has one central rule, summarized as “don’t call us, we’ll call you”. Based on the metaphor of a wannabe actor awaiting a casting call, the principle switches the control flow from the program to the system running it. This is a popular technique in event loop programming, where the program waits around for the next event and handles it accordingly.

The amateur actor can do nothing but wait around for the next casting call. It won’t do any good to call the casting office, because the actor hasn’t been selected yet. The concept is the same for your app. Cocoa and iOS are running your app and the framework will call you when the time is appropriate.

This idea is central to Cocoa development, which often turns into finding the right delegate method to implement.

Creating a New Project

In this chapter we’ll start building our app using the Single View Application template and take a quick tour of Xcode. If you’re already familiar with Xcode, then feel free to simply create the default project and skip the tour.

We begin the same way every app begins, by launching Xcode and selecting File > New Project. Choose the Single View Application template from the iOS section. With this template Xcode will create a project with one view controller and a storyboard.

Single View Application Template

On the next screen, Xcode prompts you to enter a project name and provide some additional metadata. The project name you enter here will be the name of the app, as it appears on an iOS device.

You also must enter an organization name and identifier. The organization name is usually a company name or your name. The organization identifier becomes the bundle identifier for the app, as shown in the uneditable text label. We’ll get more into bundle identifiers later, but it’s common practice to use reverse DNS notation when selecting, for uniqueness.

For language, select Swift. In the devices dropdown, you can choose iPhone, iPad and Universal. Feel free to choose whatever device you’d like. We’ll be using Auto Layout and Size classes so in the end the platform shouldn’t matter for our app. Later on, you can change the supported devices through the project settings.

On the final screen, Xcode prompts for a location to save the project. You are also given the option for creating a Git repository inside the project folder.

Xcode Tour

With the project created, Xcode presents the main project window. On the left is the navigators pane and on the right the utilities. The project navigator is selected, with a list of files inside the project. The main content window will change to reflect the file selected in the navigator. You can switch to other navigators, such as Debug, using the buttons at the top.

Let’s take a moment to look in the project navigator at the files Xcode created for us.

Initial Project View

In the project there are two types of files: Source code and Resource files. Source code files contain code in the Swift language. Resource files are everything else; Storyboards, XIB files, and Images. Resource files are the non-executable pieces of the app. (Technically, executable pieces are generated from Storyboards and XIB files, as these are serialized into Classes, but for the most part, they are static resources).

Let’s take a look at each file in the Project Navigator.

  • AppDelegate.swift: The AppDelegate is the entry point for a Cocoa Touch application. It’s the first class created after iOS finishes launching your application. It’s the responsibility of the AppDelegate to help out the UIApplication object, when delegated to. This happens at crucial moments during the application lifecycle, most notably during launch and termination. In the default Single View Application template, the AppDelegate doesn’t do much, except implement the required methods. This is because our Storyboard helps us get off the ground, and loads the initial view controller– more on that in a moment.

  • ViewController.swift: One subclass of UIViewController has been created by default, named ViewController. This view controller doesn’t do anything at the moment. All the configuration is done in the Storyboard.

  • Main.storyboard: The Storyboard created by default is called Main. It has one view controller instance of ViewController that is configured as the initial view controller. The initial view controller was initially loaded and visible on screen when the app finished launching. Because our AppDelegate doesn’t instantiate any view controllers itself, the Storyboard needs to designate an initial view controller. Otherwise the app will have no visible interface when it finishes launching.

  • Images.xcassets: This is the asset library for images. By default there is one asset for an App icon. An asset can exist in more than one size and provides support for retina resolutions. With asset collections, different resolution images for the same asset can be grouped together.

  • LaunchScreen.xib: This view is shown briefly on launch. By default it contains the metadata you entered you created your project. It’s intended that you replace or change the launch screen prior to shipping your app. In earlier versions of iOS, the developer provided static images that were briefly shown as the app was launched by Springboard. Starting with iOS 7, these images have been replaced with a XIB file. This allows one LaunchScreen to dynamically resize for different platforms and size classes.

  • Info.plist: A plist or property list is a dictionary of key/value pairs that can be archived to disk for storage. Often overlooked, the Info.plist is a key component to getting an app up and running. There are two important entries in the Info.plist that are used during application launch. One entry references the LaunchScreen.xib and another references the Main.storyboard. Xcode will format the keys in the Info.plist to a human readable string, making it easier to find and set the key you’re looking for. You can also right click the plist and show the raw key/values, such as UILaunchStoryboardName and UIMainStoryboardFile.

Take a few moments and look over some other sections within Xcode. Get familiar with the navigation panes. It can be helpful to close either the navigation or utilities section using the collapse buttons in the upper left.

Xcode can be complex and takes some getting used to. Thankfully, Apple provides some great documentation to help us along. We should have enough to get ourselves started, but be sure check out the Xcode Basics Help for a detailed walkthrough.

Build & Run

Next we’ll run the app on the simulator and see what it looks like. Under the Product menu in Xcode, you’ll find options for building and executing your app. There are a few ways to execute the app. The common way, selected via the Run option, will run the app on the simulator. There are also options to run unit tests, profile the app, or analyze the code.

Select Product > Run to run you app on the simulator. You should see the launch screen presented quickly, followed by a white view from the initial view controller. The app can also be run using the Play button in the upper left of the Xcode window, or by using the ⌘R keyboard shortcut.

You can change the device type of the simulator the app will run on by using the device button in the jump down. You may not see all devices listed. To add another simulator device type, you can use the Window > Devices menu option. This will bring up the devices available. Use the plus button in the lower left to add a new type.

Storyboard

Let’s make a small change to the background color of the main view. This will help get us a little more familiar with Interface Builder, the graphical editor component of Xcode. In earlier versions, Xcode and Interface Builder were two independent applications. They worked together, but to modify a View, you had to open a different program. Since Xcode 4, Interface Builder has become a part of Xcode. Some still think of it as a separate program, but really it’s another editor inside Xcode.

Interface Builder creates XIB and Storyboard files that describe how different interface components fit together on a graphical interface. This includes defining what labels are used, what images are shown, and how elements should resize on different devices.

It's common to see NIB and XIB files referred to as the same file type, but they are in fact different. NIB is short for NeXT Interface Builder and is the original file format from NeXT. XIB is a newer file format introduced by Apple in Xcode 4.

Start by opening the Main.storyboard file.

Storyboard inside Interface Builder

You should see one view controller on the canvas. This is our initial view controller, represented by an arrow on the left side. The document outline on the left presents a hierarchical list of elements for each view controller. All view controllers must have one view, at a minimum. This is all our view controller has at the moment.

Dig into the View Controller hierarchy and select the View. Then open the Attributes inspector on the right and change the views background color using the dropdown menu. Pick any color you’d like, and run the app again. Verify your color shows up instead of the white color.

Change View background color

Congratulations! You’ve made your first small change in an iOS app.

Becoming comfortable navigating within Xcode and Interface Builder will take some time. It’s important to become familiar with the utilities pane, because the contents will change depending on what file is selected. It may help use to View > Navigators menu option and learn the navigators by name.

The Debug Console

When using Xcode, any time the app is running on the simulator or a device it is (usually) running in DEBUG mode. There are two default execution modes: RELEASE and DEBUG. When an app in compiled in DEBUG mode, a path back to your original source code is maintained through additional symbols. When running an app through the debugger, normal program execution can be paused at certain points within your code. This allows you to step through your code as it executes each line, and see the state of the local variables.

The console is probably the most important part of the debugger. It’s where Xcode will log crash reports and relevant error messages. Any println or NSLog statements will appear in the console. To activate the console, toggle the bottom section widget. The console is on the right side of the bottom tray, with the variable state window on the left.

A breakpoint will pause a program at a specific line of code. Execution is stopped before the line of code is run. By stopping the program at key points during the execution, we can follow the logical execution and track down bugs.

Breakpoints can also be associated with an exception, so that anytime a line of code triggers a runtime exception, Xcode will jump to the point in question. Having an exception breakpoint turned on helps to immediately point out which line of code has triggered an exception.

Using the Breakpoint navigator, click the + button in the lower left and select ‘Add Exception Breakpoint’. A new breakpoint will appear in the breakpoints list. By default, the breakpoint is set up to stop execution any time an exception is thrown. You can edit this by double clicking on the breakpoint in the list. You can also turn the breakpoint on or off by clicking on the activation light in the list.

Add exception breakpoint

The debugger is also a great tool for exploring a new codebase. By setting breakpoints in interesting functions, and then exercising the code, you can get a feel for how the function is called and by what classes. This can help you develop a feel for how an app or library works from the inside out.

The View Controller

In this chapter we will start building the user interface for our app by adding a table view. By implementing a table view data source, we’ll learn how to display basic information inside table rows. The data source we construct will be independent from our view controller. At the end we’ll take a moment to set up a git repository so we can keep our project under version control.

Introducing UIViewController

UIViewController lies at the heart of any iOS app. They are the guts behind the user interface. In an MVC architecture, view controllers play the role of traditional controller objects. They control the content on screen and what happens during interactions with content.

A view controller manages a view or a set of views. The managed views may be loaded from a NIB or Storyboard or they may be created programmatically when the view controller is initialized. View controllers can also be composed together using an approach called containment, where each view controller manages an area of content on screen.

When you create a view controller, you do so by subclassing UIViewController (or a descendant of) and implementing methods necessary to present and control your content. UIViewController does much of the heavy lifting for you as it undergoes a view loading lifecycle. You’ll use special methods during the view loading lifecycle to display your content.

Method Description
viewDidLoad Called only once after the view is initially loaded. When this method is called, all outlets will be connected and the view property will be set. The frame on the view may be incorrect because the view is not yet on screen.
viewWillAppear Called before the view is about to appear on screen. This method could be called more than once if the view has been previously shown. This view is not yet on screen.
viewDidAppear Called right as the view appears on screen. The methods viewWillAppear and viewDidAppear work in tandem. At this point, the view is on screen and has a correct frame.
prepareForSegue Called prior to any segue occurring from the view controller.

Adding a Table View

Early on, the table view was known as a workhorse in iOS. By providing a simple mechanism for displaying data in rows while allowing for a range of customizing, the table view became an essential fixture is most iPhone apps. Today the workhorse title might be shifting to the collection view, but learning how a table view works and the abstractions behind model data are important to Cocoa.

Open the Main.storyboard and select the View element on the view controller. Find a table view element from the object browser on the left and drag it out on to the view. You’ll see the table view change shape as you begin to drag the element closer to the view and guidelines will appear. Use the guidelines to center the table so it’s in the middle of the view. Before adding constraints, it’s helpful to have the view positioned correctly.

Next add AutoLayout constraints so the table is pinned to the margins of the super view and takes up the full screen. These constraints will instruct the table view on how to resize for various screen sizes.

There are two methods for laying out view objects on iOS: frame-based layouts and AutoLayout. Before AutoLayout, you had to lay out a view hierarchy using frames, auto-resize masks, and run manual calculations. AutoLayout was introduced in iOS 5 as a constraints-based layout engine.

AutoLayout allows you to describe relationships between UI elements using constraints. You can also describe fixed attributes about a single object, such as height or width. In practice, the constraints can be thought of as limitations on the position of two elements. For example, two elements might need to remain ten points apart, regardless of content length.

With the introduction of size classes in iOS 8, AutoLayout has become a central component to developing modern iOS apps.

To help think about AutoLayout and Size classes, consider the following example. Imagine a room in a house with a bunch of furniture– could be any room. Now imagine how you might arrange the furniture if the room were larger or smaller in size. Perhaps it’s a living room, and if it suddenly expanded wider, you’d move the couch back further. Or maybe it’s a bedroom that shrinks and the desk needs to be moved to the foot of the bed.

This repositioning is largely what AutoLayout is all about. For each element on the user interface, you define how it should realign and reposition itself as the “room” changes size.

Instead of a UITableViewController, we’re using a regular UIViewController and with a UITableView inside. It’s possible to use either technique. The pure view UIViewController approach provides more flexibility, but it requires us to define more specifics about table cell and data source objects. It’s a little more work, but that’s ok.

Creating an IBOutlet

Elements in a Storyboard and XIB file are connected to pieces of code by Actions and Outlets. An Action connection is used to send a message from a control on the Storyboard to a method you’ve implemented, usually on the View Controller. Conversely, an Outlet connection allows you to reference user interface elements in code by sending them messages or changes properties.

As an example, consider a typical app. It might have action connections from buttons to trigger events and outlet connections to labels and text fields to show data. In our app, the view controller will use an outlet to the table view to configure properties on the table, like the data source and delegate.

You can define an IBOutlet manually on the view controller and then wire it up in Interface Builder. Or you can use the Assistant view and control-drag from the table view onto the associated code file, creating an IBOutlet and wiring it up in one step. However, this process can be cumbersome on smaller screens, and even on larger ones, it can be easier to define the IBOutlet first.

Using a Custom Data Source

A data source is an object that provides some data set to a view for display, such as a table view or collection view. The data could be any collection of items: names, restaurants, comments, menu actions, etc. The data source pattern is closely related to delegation in that a table view delegates the responsibility of displaying data to another object. On its own, a table view knows all about scrolling through a list of items, but it uses a data source to figure out what each item in the list is.

A table view can represent sectioned or grouped data items in a two-level hierarchy. For instance, you could model a list of car manufacturers and cars built using a table view. This abstraction is built upon using an NSIndexPath which consists of two parts: a section and a row. A table view uses this two-phase lookup when referring to items in its list. Your data source is expected to model data using NSIndexPaths.

The data source must handle three responsibilities on behalf of the table view:

  • Provide the number of sections the data is segmented into
  • For each section, provide the number of rows or items in that section
  • For each row within each section, create and configure a table cell to represent the associated data

These responsibilities correspond to three methods in the UITableViewDataSource. In a moment we’ll look at implementing these methods on our data source.

Table view and Data source

While the view controller could act as a data source, let’s instead follow a pattern championed by many, and create a data source object thats independent of our view controller. This creates a cleaner separation of concerns and promotes lighter-weight view controllers.

The data source object should be a subclass of NSObject and conform to the UITableViewDataSoure protocol. It will maintain a collection of Phase objects, but for now a stub implementation is sufficient. Additionally, the data source will maintain a weak reference back to the table view. This reference will be used to refresh changes.

Select File > New File… and choose a Cocoa Touch class from the iOS Source template. Change the subclass to NSObject and give your data source name, such as PhasesDataSource. With the data source file created, it’s time to conform to the UITableViewDataSource protocol.

class PhasesDataSource: NSObject {
    
}

extension PhasesDataSource: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = "Moon Phase Cell"
        return cell
    }
}

Conforming to the UITableViewDataSource protocol requires that an object supply information about how many rows and sections of data there are, and when asked to, provide a table cell for each row. For our moon phase data, we’ll use one section and a row for each forecasted phase. We don’t have any real model data yet, so for now we can just enter some stub data.

We also must return a UITableViewCell for every row. The table view will recycle cells as they scroll out of view, so we don’t create a new cell for each row. Instead we grab a recycled cell by dequeueing one from the table view. If table view doesn’t have any recycled cells, it will make a new one for us. Set text on the label to any string for now.

This is the basic stub implementation until we have real data to work with.

In addition to the UITableViewDataSource protocol, add a weak reference to the table view and register a cell identifier when the table view is set, and call reloadData().

class PhasesDataSource: NSObject {
    fileprivate weak var tableView: UITableView? {
        didSet {
            self.tableView?.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
            self.tableView?.reloadData()
        }
    }
}

Back in the view controller, create a lazy reference to the data source and connect the table view to the data source in viewDidLoad:

class ViewController: UIViewController {
    fileprivate lazy var dataSource: PhasesDataSource = {
        return PhasesDataSource()
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // connect data source with table view
        self.dataSource.tableView = self.tableView
    }
}

After selecting Build & Run, you should see a full screen table view with ten rows. At this point there is some basic functionality in the app. A table is appearing and the data source has been properly wired up.

The View

The job of the view is to display information and capture user input. Information is shown using labels, tables, images, and all of the typical interface elements. User input is captured from text fields and buttons, and is relayed on to the controller or view-model. In a practical sense, the view is the only part of your app the user can see or interact with.

In our app, the view will include an icon for the moon phase, labels for the rise and set time, and a table with future phase dates, such as new moon or first quarter.

Table Header View

The table header needs to display the Moon phase so we’ll create a UIView subclass with a few labels for the data to display. Instead of defining the table header inside the storyboard, we’ll use a NIB file, and create the header programmatically inside viewDidLayoutSubviews.

Begin by creating a new NIB file using the User Interface > View template. Position labels on the view for showing the moon icon, temperature, and summary. Add the appropriate constraints. It is helpful to add the minimum number of constraints to a view, and no more.

Table header view

AutoLayout Constraints

When considering what constraints to add, the first question to ask is how the subviews should resize and reposition for different devices. For the table header view, we want the phase icon to remain centered at the top with the phase name centered and positioned below. The moon age and illumination label will be centered horizontally and lie below the phase name. The moonrise and set time will be left aligned at the bottom of the view.

Remember that by default we’re looking at the Any/Any size class, and the canvas is 600x600. As you add constraints, try to imagine how you want the labels to adjust for different devices. Try to position constraints for the default size class first and then examine the layout in other size classes and make adjustments. You can see how the different layouts look by switching the size classes at the bottom of Interface Builder.

Loading From a NIB

With the NIB file created and the labels positioned using AutoLayout, next create a UIView subclass. Because this view will be associated with our NIB file, it’s helpful for both to share the root name– LunarHeaderView.xib and LunarHeaderView.swift for example.

Back in the NIB file, change the class type of the header view. It should match your custom class name instead of UIView, which is LunarHeaderView is this example. Then add an outlet for each label to the UIView subclass and wire up the connections in Interface Builder.

class LunarHeaderView: UIView {
    @IBOutlet var phaseIconLabel: UILabel!
    @IBOutlet var phaseNameLabel: UILabel!
}

The header view won’t appear until it’s created and added on to the table view. Declare a property on the view controller that will lazily initialize the header view. The NIB can be loaded directly from the main bundle. We can use an optional and cast the first object in the NIB to a ConditionsHeaderView. If the cast succeeds, then return a valid header view, otherwise nil.

class ViewController: UIViewController {

    ...

    fileprivate lazy var headerView: LunarHeaderView = {
        let nib = Bundle.main.loadNibNamed("LunarHeaderView", owner: self, options: nil)
        guard let headerView = nib?.first as? LunarHeaderView else {
            fatalError("Could not load LunarHeaderView from nib")
        }
        
        return headerView
    }()

    ...
}

There are several points during the view controller lifecycle to add the header view to the table. Because the header view frame must be set to match the table view, the header view should only be set up once the table view frame is accurate. With universal apps and size classes, this point becomes even more important.

We’ll use viewDidLayoutSubviews to initialize the header view and set its frame to match the table view. Finally, we’ll set the tableHeaderView on the table view. At this point in the view lifecycle, the table view has been laid out and has an accurate frame.

class ViewController: UIViewController {
    
    ...

    override func viewDidLayoutSubviews() {
        self.tableView.tableHeaderView = self.headerView
    }

    ...
}

Phase Table View Cell

Along a similar line as the table header, define the UITableViewCell subclass with an associated NIB file. The cell will represent an upcoming lunar phase and contain labels for a moon icon and date. The finished result will look something like this:

A lunar phase table view cell

Begin by selecting File > New > File… and choosing the Cocoa Touch Class template underneath iOS > Source. After selecting Next, enter UITableViewCell in the subclass field, and give the subclass an appropriate name, such as PhaseTableViewCell. Be sure and check the box to create a NIB to make things easier– if you forget, you can always manually create the NIB later on.

It’s my preference to define @IBOutlets in code first and wire them up manually later in Interface Builder. We’ll add two outlet labels for the moon phase information.

class PhaseTableViewCell: UITableViewCell {
    @IBOutlet var iconLabel: UILabel!
    @IBOutlet var dateLabel: UILabel!
}

Next, open up the NIB file for the table view cell. Add a UILabel for a moon phase icon and another UILabel for a date string. Constrain both labels along the vertical center. The icon label is then constrained with a leading space, the date label with a different leading space.

Use the guidelines to roughly position UI elements in a view. Then select each element individually and add constraints. It is helpful to pick elements towards the edges and move inward, but each view is different. Look at the overall alignment structure you wish to achieve, determine how each label should flow for different size classes, and add the appropriate constraints.

A UI element without any constraints will be absolutely positioned.

Constraints on Table Cell

With the two labels properly constrained, return to the PhaseTableViewCell subclass and implement the awakeFromNib method. In this method we’ll clear out the text icon and date labels and set the selection style to none.

class PhaseTableViewCell: UITableViewCell {
    @IBOutlet var iconLabel: UILabel!
    @IBOutlet var dateLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()

        self.iconLabel.text = ""
        self.dateLabel.text = ""
        
        self.selectionStyle = UITableViewCellSelectionStyle.none
    }
}

That’s probably enough for now. It’ll get us started with a custom cell. Later on we’ll come back to this implementation, and look at what’s missing.

Using a Custom Font

There is a fantastic font called Weather Icons that was created by Erik Flowers. The font is available in several file formats, including True Type. This make it easy to incorporate the font into an iOS project.

First add the font to the Xcode project. Make sure it’s included as part of the app target underneath the Target Membership pane. Once the font is added, you need to specify that it’s available to the app by modifying the Info.plist. Add a new row for “Fonts provided by application” and then enter the full font name. In the end, the plist entry should match the following.

Info.plist defining a custom font

Once the font file is available inside the app bundle, a weather icon can be used by setting the correct unicode character on the UILabel. The UILabel will of course need its font set to the Weather Icon font. Unicode characters for each weather icon can be looked up from the CSS file.

Here’s an example for using the sunny day icon.

self.label.font = UIFont(name: "Weather Icons", size: 20.0)
self.label.text = "\u{f00d}"

Note the escape character \u and the {} brackets surrounding the actual unicode, in this case f00d.

To make things easier, we can create an extension on String to return a unicode character for an icon name.

extension String {
    var symbolForMoon: String {
        switch self {
        case "new moon":
            return "\u{f095}"
        case "first quarter":
            return "\u{f09c}"
        case "full moon":
            return "\u{f0a3}"
        case "last quarter":
            return "\u{f0aa}"
        default:
            return self
        }
    }
}

With the extension defined, we can map between icon names and unicode characters. Now it’s simply a matter of changing the text labels to use the custom font; we’ll handle this later on as the build out the app more.

Styling the UI

There are advantages to styling the UI in code rather than inside a NIB and Storyboard. That’s not to say don’t set font sizes or colors, only that it can be easier in code. Navigating to a line of code to change a property is easier than flipping through detail panes in Interface Builder. You should be familiar with both techniques.

Fonts that have been added are available in Interface Builder. We can use the Weather Icons font directly in the NIB.

We’ll also enable paging so the user can quickly scroll between the current moon and phases. Paging makes the user experience a little nicer, by preventing the table view from showing half of the upcoming moon phases.

override func viewDidLoad() {
    super.viewDidLoad()

    ...

    self.tableView.pagingEnabled = true
    self.tableView.rowHeight = 44.0
}

Turning our attention to the header view, next we’ll set text color on labels.

Implement awakeFromNib in the conditions header view. This method is called when the view is unwrapped from the NIB file and said to be awoken. At this point all IBOutlet have been wired up and properties can be set to on. Be sure to call the super method first in your awakeFromNib implementation.

class LunarHeaderView: UIView {
    ...
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        self.phaseIconLabel.text = ""
        self.phaseNameLabel.text = ""
    }
}

The same steps are taken with the table cell. Implement awakeFromNib and set text colors and a cell background color. Here we also set the table cell selection style to .none so the cell won’t highlight on tap. This styling could also be done in Interface Builder, but it can be more clear in code.

class PhaseTableViewCell: UITableViewCell {
    ...

    override func awakeFromNib() {
        super.awakeFromNib()
        
        self.iconLabel.text = ""
        self.dateLabel.text = ""
        
        // TODO: font
        
        self.selectionStyle = UITableViewCellSelectionStyle.none

        // TODO: text colors
    }
}

With a custom table cell we should also consider implementing prepareForReuse. In our case we’ll skip this step. We won’t be reusing phase cells because all ten cells will be dequeued at once. Secondly, we won’t be adjusting cell attributes unrelated to content; our implementation of cellForItemAt will update all label text values and nothing else.

The Model

The model is responsible for the business logic of your application. It determines how information is represented, stored, and retrieved. The model is the guts of your app; it’s the domain specific data associated with the problem your app solves. In a todo list manager, the model would include the individual items and the list. It would include attributes about the item such as what needs to be done and by when.

At this point we have the basic user interface wired up, but the app only displays dummy data because we haven’t setup a model yet. The model layer will define the data points about the Moon and significant lunar phase dates, such as when the next full moon is. The view controller will create and own one instance of the model.

For every application, the model layer will be different. When building an app that fetches data from an API, it’s helpful to look at the API endpoints and the data returned to start defining your model. We’ll be interacting with the Aeris Weather API, so let’s examine the response format for one of their endpoints.

Using cURL and HTTPie

Command line tools like cURL and or HTTPie are an excellent way to communicate with an API and begin to play around with the responses. Many APIs document their endpoints using cURL commands, such as GitHub or Spotify. When diagnosing problems with client and API communication, using tools like cURL allow for a baseline comparison and help point to where the problem lies.

On macOS, cURL is best installed using Homebrew.

HTTPie is an alternative to cURL that provides a cleaner command line interface with syntax highlighted responses. It’s written in Python and available via Homebrew.

Registering for an API key

Before we can communicate with the API, we need to register for an account on the Aeris website and create a new application. Aeris uses client-less an OAuth 2 authentication scheme. We need a client_id and client_secret before we can make API requests.

The free developer plan offered by Aeris is fairly extensive and contains access to all the information needed to show Moon phases. The rate limits are high enough for a personal hobby app, capping out at 750/day on the free tier.

After signing up for API access, the next step is to create an app associated with Aeris. The documentation on the API Application/Website Registration describes the steps you’ll need to take. First choose an Application Name– the name of your iOS project or app is fine to us. Then enter an Application Domain/Identifier, using reverse DNS notation. If you have an organization name or website, then enter those in the fields provided. You’ll find you need to pick an organization name of your choosing before the form will allow you to continue.

The callback URL is not used by the Aeris API. When interacting OAuth 2.0 APIs, such as GitHub or Reddit, it’s called the redirect URL and can be used as a re-entry point into your application, through the application:openURL delegate method. In a more complex implementation of the OAuth protocol that requires the client secret to be negotiated, this is the mechanism for exchanging tokens.

Examining API responses

Open up a terminal and use cURL or HTTPie to request moon phases for some location. You’ll need to have your client ID and secret associated with your registered app on the Aeris website.

$ http "https://api.aerisapi.com/sunmoon/47.6097,-122.3331?client_id=WXYZ&client_secret=STUV"
HTTP/1.1 200 OK
Access-Control-Allow-Headers: origin, x-requested-with, content-type
Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Cache-Control: max-age=3600
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 426
Content-Type: application/json;  charset=utf-8
Date: Tue, 03 Mar 2015 05:35:08 GMT
Expires: Tue, 03 Mar 2015 06:35:09 GMT
Pragma: public

{
    "error": null, 
    "response": [
        {
            "moon": {
                "phase": {
                    "age": 12.51, 
                    "angle": 0.49, 
                    "illum": 94, 
                    "name": "waxing gibbous", 
                    "phase": 0.4236
                }, 
                "rise": 1425338580, 
                "set": 1425301440, 
            },
        }
    ], 
    "success": true
}

There’s a bit more to the response than that, but the above contains enough data to begin to conceptualize the model. The JSON returned contains error, response, and success objects, at the top level. We’re interested in the response. Within the response is a moon object with data points about the current moon.

See the documentation on the Aeris API for more details.

For the lunar phases, we need to hit a different endpoint, /sunmoon/moonphases/. We also want to include a limit parameter for the number of phases to return.

$ http "https://api.aerisapi.com/sunmoon/moonphases/47.6097,-122.3331?client_id=WXYZ&client_secret=STUV&limit=2"
HTTP/1.1 200 OK
Access-Control-Allow-Headers: origin, x-requested-with, content-type
Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Cache-Control: max-age=7200
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 279
Content-Type: application/json;  charset=utf-8
Date: Tue, 03 Mar 2015 20:29:54 GMT
Expires: Tue, 03 Mar 2015 22:29:54 GMT
Pragma: public

{
    "error": null, 
    "response": [
        {
            "name": "full moon", 
            "timestamp": 1425578794
        }, 
        {
            "name": "last quarter", 
            "timestamp": 1426268969
        }, 
    ], 
    "success": true
}

The response is abbreviated slightly, but we see an array of phase objects with a name and timestamp attribute.

We can make two API calls for two sets of data and present the results together in the same UI. Because we’ll be making networking requests asynchronously, we won’t know when both requests have finished. This ends up being a typical pattern with network apps. You make several API calls, join the resulting data together, and present it all at once.

A DispatchGroup can be created and used to wait for all requests to finish. This requires that each request enter the group prior to executing and leave the group upon completion. We’ll see an example of this later, but for now remember that our model is built up from two API calls, one for the current moon and another for a list of moon phases.

Defining Model Objects

We can now begin to construct our model objects. We’ll define a Moon type and a Phase type.

struct Moon {
    let phase: String
    let age: Int
    
    let rise: Date
    let set: Date
}

struct Phase {
    let name: String
    let date: Date
}

These types are defined as structs because we want to use value types. The moon phases won’t change once they are determined. We might find a new set of phases at a later point in time, but we’ll simply replace the value for the current set with ones. Using value type in place of reference types is a subtle distinction between Objective-C and Swift.

We have enough model objects defined to begin connecting a dummy model and return hard coded data. Later we’ll install the plumbing and build the mechanism for finding the location and moon phases.

Create a new class named LunarPhaseModel with a computed variable for returning the current moon and phases. This model will mostly be a stub implementation until more functionality is built below.

class LunarPhaseModel {
    var currentMoon: Moon {
        let moon =  Moon(phase: "full moon", age: 14, rise: NSDate(), set: NSDate())
        return moon
    }

    var currentPhases: [Phase] {
        let phase1 = Phase(name: "first quarter", date: NSDate())
        let phase2 = Phase(name: "full moon", date: NSDate())
        let phase3 = Phase(name: "third quarter", date: NSDate())
        return [phase1, phase2, phase3]
    }
}

Our view controller will create a new instance of LunarPhaseModel. This model will be passed off to the data source, so the table view correctly displays lunar phases. The model will also be passed off to the conditions header view, in the form of a view-model. In this way, we’ll pull data from one model and use it in two places in the interface.

class ViewController: UIViewController {
    
    ...

    fileprivate let model = LunarPhaseModel()

    ...

    fileprivate lazy var dataSource: PhasesDataSource = {
        return PhasesDataSource(model: self.model)
    }()

    ...
}

Let’s also change the initializer on our data source and modify it to return row counts from the phases array.

class PhasesDataSource: NSObject {
    fileprivate var phases: [Phase] = []
    fileprivate let model: LunarPhaseModel
    
    init(model: LunarPhaseModel) {
        self.model = model
        super.init()
    }

    ...

}

extension PhasesDataSource: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.phases.count
    }

    ...
}

Additional Resources

For information on the cURL syntax, see the tutorial Using cURL to automate HTTP jobs. The syntax can become verbose so it’s helpful to create or refer to cheat sheets to remember commands.

The HTTPie README describes how to make requests against an endpoint. There are cheat sheets available too.

The View-Model

The job of the view-model is take the model data and transform it into a representation intended for user display. The view-model moves presentation logic outside of the View Controller and model layer. Presentation logic could be number formatting for a currency label, string concatenation for showing proper names, or showing a placeholder image when an avatar is missing.

We’ll design our view objects to configure themselves when given a view-model. This will be done with a property observer. When given an instance of a view-model, the View will lay out and display its subviews based on the data contained.

Just like in the model, we can use value types to define the view-model, because it won’t change once initially defined.

Creating PhaseViewModel

Let’s begin with a PhaseViewModel which needs to return information for displaying moon phase cell. Because the cell has labels for date and icon, our view-model needs to return formatted string values for these labels. The presentation logic for displaying the cell will include formatting dates and finding the correct icon font.

The PhaseViewModel is created as a struct because it makes sense to use a value type for the view-model. Once initialized with a model object, the view-model is not going to change. It’s going to display and format the same model data for its lifetime. When we need to display another piece of model data, we’ll simply create another view-model object for it.

struct PhaseViewModel {
    fileprivate let phase: Phase
    
    init(phase: Phase) {
        self.phase = phase
    }
    
    var icon: String {
        return phase.name.symbolForMoon
    }
    
    var date: String {
        return self.formatter.string(from: phase.date)
    }
    
    fileprivate var formatter: NSDateFormatter {
        let formatter = DateFormatter()
        formatter.dateFormat = "EEEE, MMMM d yyyy"
        return formatter
    }
}

The PhaseViewModel is initialized with a Phase instance, which is kept as a private constant. The phase constant is marked as a private so the model object isn’t directly exposed, only methods that act on the data. This is an example of Encapsulation.

Two computed properties are defined for each label we wish to populate. This is where the presentation logic is implemented. When displaying the icon label, the name property on the model is used in conjunction with a String extension to return a lunar icon symbol. The date string is derived from the date model property by using an DateFormatter.

The date formatter declaration is a little wasteful because it’s created each time. A better idea might be to use a shared date formatter for all view-models. Then each view-model wishing to format a date (in the same way) could reuse a same date formatter. However, we leverage the simple approach without a huge penalty because our use case won’t create a significant number of formatters.

One important takeaway is that the view-model, as defined above, is a value type. It can only be initialized with a phase model and cannot be modified afterwards. The computed properties exposed are only getters. This helps establish the view-model as an immutable part of our application design.

Using PhaseViewModel

To use the PhaseViewModel we need to modify the PhasesDataSource and PhaseTableViewCell. First a viewModel property is added to the PhaseTableViewCell. We’ll implement a didSet property observer and configure the label text when the view-model changes.

class PhaseTableViewCell: UITableViewCell {
    @IBOutlet var iconLabel: UILabel!
    @IBOutlet var dateLabel: UILabel!
    
    var viewModel: PhaseViewModel? {
        didSet {
            self.iconLabel.text = viewModel?.icon
            self.dateLabel.text = viewModel?.date
        }
    }
    
    ...
}

Then the data source is modified to create a view-model as each cell is dequeued.

extension PhasesDataSource: UITableViewDataSource {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)
        
        guard let phaseCell = cell as? PhaseTableViewCell else { return cell }
        phaseCell.viewModel = viewModel(for: indexPath)
        
        return cell
    }
}

Result Type

So far we’ve mostly kept to established Cocoa patterns that held true even with Objective-C. One of the exciting things about Swift is how the ecosystem can change with the new language constructs and paradigms available. We can use some of the functional aspects of Swift and bring new designs to the table.

Let’s take a moment to discuss some existing types in Swift and look at how they are implemented in the language. Booleans and optionals might not seem as similar at first, but they are both implemented as Enumerations.

Optional

We’re used to declaring an optional using the shorthand ? notation, but it’s also valid to use the full Optional keyword. For example, here are two ways to declare an optional UIImage.

var image1: UIImage?
var image2: Optional<UIImage>

Parts of the Swift library are exposed through something akin to a header file. Command-click on a standard type to view the definition in the Swift framework. Weighing in at almost 10,000 lines, this isn’t an ideal way to learn about Swift, but it does provide some insight into how Optionals work.

enum Optional<T> {
    case none
    case some(T)
}

Optional is defined as an enum with two possible states, none and some. Associated with the some state is a value of type T. So essentially we have an enum that refers to nothing or some type T.

The idea of representing nothing or some value is used in Objective-C APIs that return nil in place of some real value. Because the real value could be of any type, the Optional use accepts a generic parameter.

Boolean

A boolean value is either one or another. It is true or false, YES or NO. It follows then that the Boolean type could be implemented as an enum with two states.

enum Boolean {
    case true
    case false
}

Similar to an Optional is the idea of an Either type, which could either be one type or another. This comes from Haskell, which uses the Either type to help report information about why a value is missing or not found– additional handling.

enum Either {
    case left<T>
    case right<U>
}

Defining custom types

We can build on the idea of Optionals and create a Result type, containing either some generic result or a failure describing why a result could not be obtained.

This turns into a very powerful idea. Since remote data may or may not exist, using the Result type allows us to represent some information or describe why the information isn’t there. Later on we’ll leverage this type to determine moon phases and location.

Firt define a Result type representing the result of some operation. This type will be generic based on the type of data we’re expecting back.

enum Result<T> {
    case success(T)
    case failure(Error)
}

Next we can define some an error type, associated with the type of operation we’re creating. For example, a network operation might fail because of a malformed responsed, a bad status code, and so on. By creating a new type that conforms to Error, we can model the different errors our app might encounter.

enum NetworkError: Error {
    case badStatusCode(statusCode: Int)
    case badResponse
    case badJSON
    case noData
    case offline
    case other(Error?)
}

Now with generics we can create a Result that returns Data or CLLocation or any type on success. If a failure occurs, it will return an Error describing the why the failure happened.

Great. We have these types defined, but how are we going to use them? We’ll use them to return the current location and moon phases. There a little bit more work in front of us, but eventually we will some types defined like this, allowing for some powerful abstractions.

typealias LocationResult = Result<Location>

typealias CurrentMoon = Result<Moon>
typealias CurrentPhases = Result<[Phase]>

typealias JSON = [String: AnyObject]
typealias JSONResult = Result<JSON>

Additional Resources

There is a Result framework by antitypical which is a move advanced by thorough exploration. The ideas shown above are derived and inspired from the projects ancestor, LlamaKit.

There’s much to the Haskell language, but if you’re interested in learning more about algebraic data types or error handling, chapter 19 in Real World Haskell and For a Few Monads More are good reads.

Finding and Tracking Location

Finding your whereabouts on a mobile device is a central and core piece of a functionality. It allows apps to provide location aware data in the context user, where ever they are. This could be a weather app providing real time forecasts or a transit app that lists arrivals times for bus stops. For our purposes, we’ll use the current location for requesting moon phase information from the Aeris API.

Apple provides the Core Location framework to find and track location on iOS and macOS. The location is found using WiFi, Cellular, and GPS radios. GPS is the most accurate but is not available on all devices. Additionally, some devices include the heading and speed in the location metrics returned.

When determining a location, updates may be given with different levels of granularity. At first a rough location will be found followed by more precise location updates, as they become available.

Our location tracker will do two things: determine location changes and send updates to interested parties. We’ll be using the Core Location framework and implementing a CLLocationManagerDelegate object to handle changes. By using reverse geocoding we can determine the current city, and package the coordinates and city name together when publishing changes.

Requesting Authorization

An app must register for with location services before using them. Doing so forces your app to present an alert where the user must grant permission to access the location services. You’ve no doubt seen this before when using iOS apps. As a developer, you are responsible for setting an entry in the Info.plist to prompt iOS to ask permission.

Starting in iOS 8, your Info.plist needs an entry NSLocationWhenInUseUsageDescription or NSLocationWhenInUseUsageDescription

Entry Description
NSLocationAlwaysUsageDescription App requests permission to always use location, even in the background.
NSLocationWhenInUseUsageDescription App requests permission to only use location when in use. This is generally preferred.

After the location delegate methods are wired up, you should see an alert the first time then app is run or reinstalled on the simulator or device. The large bold text in the alert is controlled by iOS. The subtitle text is the usage description from the Info.plist. Keep the description brief and summarize why your app needs location access.

Requesting Permission for Location

Building a Location Tracker

Next create a new subclass of NSObject called LocationTracker or something similar. First define a location object. Then define two types, one for location results and another for observer callbacks. Identifying the types to use is an important first step is creating nice abstractions.

public struct Location {
    let physical: CLLocation
    let city: String
    let state: String
    let neighborhood: String
}

public typealias LocationResult = Result<Location>
public typealias Observer = (_ location: LocationResult) -> ()

The Location type holds the physical latitude and longitude coordinates and metadata about the location. We also have a LocationResult defined an alias to Result<Location>. This type represents some result that is either a Location and a failure. Finally we have an Observer type defined a function accepting one LocationResult and returning nothing. Observers will implement this function, and it will used as a callback whenever the location as changed.

It also makes sense to define a new error type for LocationError. This type will be used to describe why a location could not be determined. Its sufficient for now to cover only the general case that no data was return for some reason.

enum LocationError: Error {
    case noData
}

With the types defined, we can move onto implementing the LocationTracker itself. Change the LocationTracker definition to conform to the CLLocationManagerDelegate protocol. If your class doesn’t descend from NSObject then you won’t be able to conform to CLLocationManagerDelegate.

Declare an optional for tracking the last result and an array to represent the observers. The lastResult variable should be initialized with a .NoData failure, because the initial location is unknown.

public final class LocationTracker: NSObject {
    fileprivate var lastResult: LocationResult = .failure(LocationError.noData)
    fileprivate var observers: [Observer] = []
    
    var currentLocation: LocationResult {
        return self.lastResult
    }

Next we’ll create a CLLocationManager as a private lazy variable and set the LocationTracker as the delegate. Then we’ll begin updating the location inside the init() method.

public final class LocationTracker: NSObject {
    ...

    override init() {
        super.init()
        self.locationManager.startUpdatingLocation()
    }

    private lazy var locationManager: CLLocationManager = {
        let locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        return locationManager
    }()

The locationManager is initialized lazily at the end of the init and a call to startUpdatingLocation is made. But we haven’t implemented any protocol methods yet for CLLocationManagerDelegate, so that’s the next step.

CLLocationManagerDelegate

The CLLocationManagerDelegate describes what methods to implement in order to receive location updates. In our case, the LocationTracker will act as the location manager delegate, so it will need to conform to the CLLocationManagerDelegate protocol.

The first protocol method to implement is locationManager:didChangeAuthorizationStatus:. If we’ve set everything up correctly in the Info.plist, when the user grants permission to use location, this method will be called.

extension LocationTracker: CLLocationManagerDelegate {
    ...

    public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedWhenInUse:
            manager.startUpdatingLocation()
        default:
            manager.requestWhenInUseAuthorization()
        }
    }
}

The next protocol method to implement is locationManager:didFailWithError where we use the error returned to create a failure result. The result is stored locally; later we’ll return to method and publish a change with the failure result.

extension LocationTracker: CLLocationManagerDelegate {
    ...

    public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        let result = LocationResult.failure(NetworkError.other(error))
        self.publishChange(with: result)
        self.lastResult = result
    }
}

The final method to implement is locationManager:didUpdateLocations. This method is called when the location updates. You may notice the plural argument locations. This method is called when an array of at least one CLLocation object. However, there may be more than one location object if for some reason previous updates were delayed.

The location update delegate method will be called on all location changes. It doesn’t make sense to update the moon phases on all location changes, because the information likely won’t change over small increments. Instead, we must determine some minimum threshold and publish significant location updates.

extension LocationTracker: CLLocationManagerDelegate {
    ...

    public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let currentLocation = locations.first {
            if shouldUpdateWithLocation(currentLocation) {
                // TODO: publish update
            }
            
            // location hasn't changed significantly
        }
    }
}

The helper function shouldUpdate:with determines the criteria for updating a location. In this case, a location is updated if a .Failure result occurred previously, or if the new location is more than 100 meters away from the previous.

fileprivate func shouldUpdate(with location: CLLocation) -> Bool {
    switch lastResult {
    case .success(let loc):
        return location.distance(from: loc.physical) > 100
    case .failure:
        return true
    }
}

Reverse Geocoding

Geocoding associates a location description (typically an address) with a latitude and longitude pair. Reverse geocoding is the opposite, where an address or location is determine from latitude and longitude. In a way, they are transformation between human and machine readable formats.

As part of CoreLocation, CLGeocoder provides a conversion between a latitude/longitude coordinate and a human readable representation. A CLPlacemark includes an address, city, state, country, but also maybe include landmark information. They can be generated programmatically or by a CLGeocoder.

Apple provides some guidelines about reverse geocoding locations, with specifics about how often request should be made and suggestions for caching locations.

public func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
    if let currentLocation = locations.first {
        if shouldUpdateWithLocation(currentLocation) {
            let location = Location(location: currentLocation, city: "", state: "", neighborhood: "")
            
            let result = LocationResult.Success(location)
            self.publishChangeWithResult(result)
            self.lastResult = result
        }
        
        // location hasn't changed significantly
    }
}

Adding observers

The LocationTracker manages a private [Observer] collection. When the location significantly changes, the observers should be notified via an Observer callback. The Observer callback is a function that accepts a LocationResult and returns nothing. Each observer will implement their own Observer callback.

To add observers to the collection, create an addLocationChangeObserver or similar that accepts an Observer object and adds it into the collection.

func addLocationChangeObserver(observer: @escaping Observer) -> Void {
    observers.append(observer)
}

To publish change to observer, implement another method called that accepts a LocationResult as input. Based on the required location change granularity, this method can determine if a location change should be published to observers. If so, the observers array is mapped over and the observer callback is triggered for each.

fileprivate func publishChange(with result: LocationResult) {
    if self.shouldUpdate(with: result) {
        observers.forEach({ (observer) -> Void in
            observer(result)
        })
    }
}

Using LocationResult

Because the location is initially unknown and might not be retrievable, it makes sense to utilize the Result type. This way the location can be represented as either unknown (and invalid) or valid. When a LocationResult is returned through an Observer callback, we can use a switch statement to find the value of the result.

let locationTracker = LocationTracker()

locationTracker.addLocationChangeObserver { (result) -> () in
    switch result {
    case .success(let location):
        let location = location
        // handle new location
    case .failure(let error):
        // handle failure
    }
}

Making Network Requests

Network communication is central to many apps. Our phones and tablets are mobile in nature and wireless communication has made the internet ubiquitous. Creating robust and fault tolerant network layers is key to building a polished app experience. As iOS has evolved through the releases, the options available for making networks requests have changed. From NSURLConnection to URLSession to several open source libraries, we’ll examine the ins and outs of fetching remote data from a web service.

One issue inherent to all network operations is latency, or the round trip time spent waiting for data to be sent and a response returned. Web servers and data centers aren’t right next door so any network request will take some time to process. Things happen very quickly inside the processor of the iPhone so the time spent waiting for a network requests is significant– think years in processor terms.

Threading and GCD

A network request will always involve some wait time. With fast connections all around, this wait time is relatively short for you and I, but for a computer, the time spent waiting for network responses is significantly longer (in relative terms). When billions computational cycles are available per second, waiting even 5 seconds for a network call is significant.

Fortunately modern day processors are capable of executing multiple blocks of code at once, on different threads. A thread can be thought of a single independent unit of work, where multiple threads can be executing work at once.

On iOS, one thread is designated the main thread and it handles all user interface operations. Because UIKit is not thread-safe all operations using UIKit must occur on the main thread.

When it comes to networking, the need for multiple threads arises because your app cannot wait around doing nothing while waiting on a network request to return. This is referred to as a blocking. Technically, you can make a blocking request, but this is not the mark of a production quality app. Best practice dictates that your user interface should remain responsive– any long running operations should be moved to another thread.

Grand Central Dispatch (GCD) is a low level framework provide by Apple for performing multithreaded programming. GCD performs the thread management itself and exposes an API for scheduling units of work using queues. The queues can have different levels of priority and there is a special queue associated with the main thread.

Multithreaded programming isn’t just for networking operations. App responsive will increase by moving any long running operations to another thread. Imagine an app that calculates the first N prime digits or one that maps chess moves from a game state. Or imagine parsing a large JSON file and inserting a several thousand rows into a SQLite database. All of these operations would be expensive and writing a naive single threaded approach may not be efficient.

GCD Example

At the core, GCD manages a set of threads for you and takes care of all scheduling. Instead of the threads, queues are made available and units of work or blocks can be scheduled or run a queue. You don’t create any threads, and you typically don’t need to create any queues. You can mostly request references to global queues that GCD is managing for you.

Let’s look at an example of using GCD that follows a call-callback pattern. With this pattern, a block with some expensive work is dispatched to a background thread, the work is performed, and a second block is dispatched back to the main thread to handle the result. This is a common pattern to use when the user interface must be updated at the end of some computation.

let queue = DispatchQueue.global()
let main = DispatchQueue.main

queue.async {
    // perform expensive operation
    
    main.async {
        // callback to main thread and update UI with result
    }
}

Different priority queues are available to help with scheduling. To change the priority, simply pass in a different priority level when the queue reference is retrieved.

URLSession

Networking is central to many iOS apps and theres many different approaches to making requests, with different levels of abstraction. Apple has provided CFNetwork, NSURLConnection and most recently URLSession. There are several open source libraries have been on top, including RestKit, AFNetworking, AlamoFire, FSNetworking, and MKNetworkKit, to name a few.

To make network requests we can rely on URLSession directly instead of turning to a larger open source solution. This will allow us to see how networking is done within Cocoa and use the APIs first hand.

Let’s begin by defining a class to act as a network controller. The network controller will define a function that accepts a URLRequest and a TaskResult callback function. Because the network requests will be made asynchronously, the TaskResult function will be used for returning a Result.

typealias TaskResult = (result: Result<NSData>) -> Void

class NetworkController {
    
    fileprivate let configuration: URLSessionConfiguration
    fileprivate let session: URLSession = URLSession.shared
    
    init(configuration: URLSessionConfiguration = URLSessionConfiguration.default) {
        self.configuration = configuration
    }

    func start(_ request: URLRequest, result: @escaping TaskResult) {
        
        let finished: TaskResult = {(taskResult) in
            DispatchQueue.main.async(execute: { () -> Void in
                result(taskResult)
            })
        }
        
        let task = session.dataTask(with: request, completionHandler: { (data, response, err) -> Void in
            guard let data = data else {
                guard let _ = err else {
                    return finished(.failure(NetworkError.noData))
                }
                
                return finished(.failure(NetworkError.other(err)))
            }
            
            guard let response = response as? HTTPURLResponse else {
                return finished(.failure(NetworkError.badResponse))
            }
            
            switch response.statusCode {
                case 200...204:
                    finished(.success(data))
                default:
                    let error = NetworkError.badStatusCode(statusCode: response.statusCode)
                    finished(.failure(error))
            }
        })
        
        task.resume()
    }
}

There’s a bit going on in the startRequest function so take a moment to walk through it. First a function is defined to process the results on the main thread. This function will be used in the future, when a result is ready. Next the configuration and session objects are created; we’ll modify these in the future. Finally a data task object is created and the completion handler is implemented. Most of completion handler is error handling for the various cases and each returns a Result.Failure with a different reason. Only in the success case do we return a Result.Success with the NSData received.

Once the task is created, the resume() function is called to start the network request.

We can take things further by defining a URLSessionDelegate object. While doing so is not strictly necessary, it will allow us to handle authentication challenges and other delegate responsibilities in the future. The delegate object can be private to our network controller.

class NetworkController {
    
    ...
    
    fileprivate class SessionDelegate: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate {
        
        fileprivate func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
            completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
        }
        
        fileprivate func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
            completionHandler(request)
        }
    }

    ...
}

We can then modify our init function to create a URLSession object using the supplied URLSessionConfiguration.

class NetworkController {
    
    fileprivate let configuration: URLSessionConfiguration
    fileprivate let session: URLSession
    
    init(configuration: URLSessionConfiguration = URLSessionConfiguration.default) {
        self.configuration = configuration
        
        let delegate = SessionDelegate()
        let queue = OperationQueue.main
        self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue)
    }

    deinit {
        session.finishTasksAndInvalidate()
    }

    ...
}

Waiting on Multiple Requests

It’s not uncommon to make multiple requests and need to wait the all to finish before proceeding. This can become complicated when each request finishes independently, taking an unknown amount of time. For example, if an activity indicator is shown, it should be dismissed when all requests have completed; how we will known when all requests have finished?

One way to solve this is to use a dispatch group, a feature of GCD that allows tasks or blocks to be grouped together. Each unit of asynchronous block enters the group before performing work, and once it’s work is finished, it exits the group. While group tasks are executing, you can wait on the group to signal that all work is done, and then continue afterwards.

Consider the code below which creates a dispatch group with two units of asynchronous work. A completion block is associated with the group which executes only after all the grouped tasks have finished. The key is that workers are responsible for entering and leaving the group themselves.

let queue = DispatchQueue.global()
let group = DispatchGroup()

group.enter()
group.enter()

queue.async {
    // do some asynchronous work, leave group when done
    group.leave()
}

queue.async {
    // do some asynchronous work, leave group when done
    group.leave()
}

group.notify(queue: queue) { 
    // block executes when all task in group are finished.
}

Nothing much happens in the code above; it’s only a stub implementation without any logic. We can expand upon it with a function that fires off request and use the group to wait on multiple requests. The code shown below is extracted from the DispatchGroups playground.

func runAsyncTask(in group: DispatchGroup) -> Void {
    let session = URLSession(configuration: .default)
    let url = URL(string: "http://www.apple.com")!
    
    group.enter()
    
    let task = session.dataTask(with: url) { (_, _, _) in
        print("finished with task")
        group.leave()
    }
    
    task.resume()
}

let queue = DispatchQueue.global()
let group = DispatchGroup()

runAsyncTask(in: group)
runAsyncTask(in: group)

group.notify(queue: queue) {
    print("all tasks done")
}

The runAsyncTask:in function accepts a DispatchGroup and performs some work with the group. The work in this case is an asynchronous network request to an arbitrary URL, in this case www.apple.com. We’re not really interested in the data and response returned, so the dataTask:with: completion handler uses unnamed parameters. As the task begins and completes, the runAsyncTask:in function enters and leaves the group.

Additional Resources

The Concurrency Programming Guide from Apple discusses GCD in detail.

Chris Eidhof has written and talked about Tiny Networking as a lightweight approach to API modeling. There is a presentation on the same subject titled “Tiny Networking: Building Micro-Libraries in Swift”.

Interacting with an API

Next we’ll design and model API interactions by building a network controller.

The NetworkController is designed to be API agnostic. It’s not tied to any specific web service. It takes an URLRequest and returns an URLSessionTask for that request.

An API can be modeled using an enum with associated values representing data passed to an endpoint or used to build a request. Consider the following example.

enum AerisAPI {
    case moon(CLLocation)
    case moonPhases(CLLocation)
}

Here we define an enum with two options, one for the moon and another for moonPhases. Both options are associated with a CLLocation value. The enum models two possible requests, and two possible states that API can be queried in.

The API enum can be extended to generate requests for an API type, which corresponding to an endpoint.

protocol Request {
    var request: URLRequest { get }
}

Consider the example below, where the associated CLLocation value is used to fetch moon information from /sunmoon or /sunmoon/moonphases. A request() function generates a NSURLRequest for each endpoint. The API requires authentication using client_id and client_secret parameters, which are added onto the URL query string when generating the request. These and other parameters remain private and the extension only exposes a request() function.

extension AerisAPI: Request {    
    var baseURL: URL {
        return URL(string: "https://api.aerisapi.com")!
    }

    var parameters: [String: String] {
        switch self {
        case .moon:
            return ["client_id": clientId, "client_secret": clientSecret]
        case .moonPhases:
            return ["client_id": clientId, "client_secret": clientSecret, "limit": "5"]
        }
    }
    
    var path: String {
        switch self {
        case .moon(let location):
            let latitude = location.coordinate.latitude
            let longitude = location.coordinate.longitude
            let queryString = query(with: parameters)
            return "\(baseURL)/sunmoon/\(latitude),\(longitude)?\(queryString)"
        case .moonPhases(let location):
            let latitude = location.coordinate.latitude
            let longitude = location.coordinate.longitude
            let queryString = query(with: parameters)
            return "\(baseURL)/sunmoon/moonphases/\(latitude),\(longitude)?\(queryString)"
        }
    }
    
    var request: URLRequest {
        let path = self.path
        guard let url = URL(string: path) else { fatalError("bad url") }
        return URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 60.0)
    }
}

extension AerisAPI {
    fileprivate var clientSecret: String {
        return "FuiP61dAfrSWi5rhRo7IbDic4qlvIVVQix0tJhaq"
    }
    
    fileprivate var clientId: String {
        return "aHR5XrkQpBJ5Yv2Pw1ki"
    }
}

The interesting logic occurs in the path function. Depending on the type of the enum, a switch builds a different url string for each enum type, in this case .moon and .moonPhase.

The client_id and client_secret will be unique to your application. Use the values given after register you application with the API.

We can now create URLRequests for retrieving the moon phases at a specific location. How might this look?

let location = CLLocation(latitude: 25.7877, longitude: -80.2241)
let phasesRequest = AerisAPI.moonPhases(location).request()

Similarly, we can request the current moon information.

let location = CLLocation(latitude: 25.7877, longitude: -80.2241)
let moonRequest = AerisAPI.moon(location).request()

This API modeling technique can be extended for other endpoints, with other associated values representing parameters. It nicely separates the specifics of one API from another.

The HTTP Verbs and REST

The HTTP protocol defines a set of verbs describing actions associated with each resource request. The most common verbs are GET, PUT, POST, and DELETE. When an HTTP request for a resource is made the verb describes the action the request should take. A GET request will return the resource; a DELETE request will instruct the server to delete the resource (if possible). We’ll get the PUT and POST shortly, but they deal with resource creation and modification.

A web application or service is typically backed by a database of some kind. For example, a web service for train arrivals and departures would use a database of timetables to serve up requests. When talking about databases, the CRUD acronym (which stands for Create, Read, Update, and Delete) describes the four essential operations of a data store. For example, records needs to be created and updated. They also need to be read when the time is right and deleted when no longer used.

HTTP Verb Database Counterpart Description
GET Read Access existing record (or resource)
PUT Create Create a new record
POST Update Update a record
DELETE Delete Delete a record

Additional Resources

REST API Tutorial is an in depth tutorial site with several great resources on learning REST. See the list of HTTP methods or status codes.

For more information on using enums to represent remote APIs, see “A tiny networking library” and “Type-safe URL routes in Swift”.

Creating Model Objects

When communicating with web services, remote objects and responses are typically modeled as JSON, which stands for JavaScript Object Notation. Despite the name, JSON is not limited to only JavaScript. JSON is described as a lightweight data-interchange format that is human readable and easy for computers to work with. Contrast this with XML, a verbose format that’s not easy on the eyes, and it’s easy to see why JSON has become to preferred format for data exchange.

Parsing JSON is the act of transforming a string representation into a JSON object or dictionary. When iOS was first introduced there was no JSON parser included. This led several open source solutions for parsing JSON that are still viable solutions today. Starting with iOS 5, Apple introduced NSJSONSerialization as part of Foundation.

The parsed JSON then needs to be transformed into model objects. Technically this is not part of the parsing process, but the two may be lumped together– especially when you’re interested in a subset of the data. With parsing handled by a library, the developers task is to transform the JSON into a domain specific model relevant to the app. The JSON may represent a newsfeed or list of friends or recently updated stories. We need to make concrete model objects and set attributes on them using the JSON representation.

Swift, Objective-C and JSON

Swift and Objective-C are very different animals. Objective-C has dynamic types, but Swift has static types. Much has been written about the benefits and downsides of both, but when it comes to handling JSON, it’s slightly more complicated in Swift. With the strict statically typed system in Swift, we cannot force objects into certain type classes without the compiler throwing errors.

JSON and Swift has been the topic of much discussion and there are several open source solutions. Instead of using a third partying library to transform JSON into model objects, we’ll instead create a static parsing function on our model objects and handle the transformation ourselves. Because we’re not sending remote objects to the server, we only have to handle the transformation one way (JSON -> Model Object) and not the reverse.

JSONResult and NSData extension

Begin by defining two typealiases for representing with JSON.

typealias JSON = [String: AnyObject]
typealias JSONResult = Result<JSON>

The JSON type is a typealias to a dictionary, with String keys and AnyObject values. This mimics the JSON structure returned from NSJSONSerialization. Next we define a JSONResult type that wraps a JSON response. This approach builds on the Result type already established.

Responses from our NetworkController are returned as Data so it makes sense to define an extension to Data to convert into a JSONResult. This extension will be used to handle the JSON conversion and make use of the Result pattern to wrap a JSON object. Even though JSONObjectWithData doesn’t return JSON object, the cast should work because of the typealias we have defined. If the cast fails or a parsing error occurs then a .failure is returned.

extension Data {
    func toJSONResult() -> JSONResult {
        do {
            let json = try self.toJSON()
            let obj = try JSONSerialization.jsonObject(with: self, options: [])
            guard let json = obj as? JSON else { return .failure(.badJSON) }
            return JSONResult.success(json)
        } catch (let error) {
            return JSONResult.failure(.other(error))
        }
    }
}

Later on when parsing the response, we’ll be able to use this extension to create JSONResult from Data.

func JSONResultFromData(_ data: Data) -> JSONResult {
    return data.toJSONResult()
}

Handling JSON

With a set of relevant attributes, the parsing function will work through the JSON dictionary, pulling out attributes and casting them to another type. If all attributes are found, with the proper type, a model object is created. However, if any attribute is missing, a model object is not created and nil is returned.

Begin by defining a MoonResult type that wraps a Moon object inside a Result.

typealias MoonResult = Result<Moon>

Next model the moon with attributes you’re interested in and create a parsing function. The parsing function in a JSON representation of the moon response and find the desired attributes inside. The function will return a MoonResult.

struct Moon {
    let phase: String
    let age: Double
    let percent: Double
    
    let illumination: Int
    
    let rise: Date
    let set: Date
}

extension Moon {
    
    init?(json: JSON) {
        guard
            let response = json["response"] as? [JSON],
            let moonObj = response.first?["moon"] as? JSON,
            let phase = moonObj["phase"] as? JSON,
            let phaseName = phase["name"] as? String,
            let age = phase["age"] as? Double,
            let percent = phase["phase"] as? Double,
            let illum = phase["illum"] as? Int
            else {
                return nil
        }
        
        let riseInterval = moonObj["rise"] as? Double ?? 0
        let setInterval = moonObj["set"] as? Double ?? 0
        
        let rise = Date(timeIntervalSince1970: riseInterval)
        let set = Date(timeIntervalSince1970: setInterval)
        
        self.phase = phaseName
        self.age = age
        self.percent = percent
        self.illumination = illum
        self.rise = rise
        self.set = set
    }

    static func moonFromJSON(_ json: JSON) -> MoonResult {
        if let moon = Moon.init(json: json) {
            return .success(moon)
        } else {
            return .failure(JSONError.badFormat)
        }
    }
}

The above example starts to illustrate why JSON parsing can get a little ugly and why many others have been experimenting with alternative techniques. If our Moon model was much more complex, the guard statement would become even larger. Or if the data was layered deeper, we’d have to dig through more intermediate attributes. This isn’t necessary a scalable technique but it works for our case and it’s simple to understand.

Parsing the Phase objects requires less attributes, but we need to loop over an array of objects in the response, one for each Phase. We can define a static function that returns a [Phase] collection from a JSON array. Similar to before, we’ll define two custom types for PhaseResult and PhaseResults to model the phases or the failure conditions.

typealias PhaseResult = Result<Phase>
typealias PhasesResult = Result<[Phase]>

struct Phase {
    let name: String
    let date: Date
}

extension Phase {
    init?(json: JSON) {
        guard
            let name = json["name"] as? String,
            let interval = json["timestamp"] as? TimeInterval
        else {
            return nil
        }
        
        self.name = name
        self.date = Date(timeIntervalSince1970: interval)
    }
    
    static func phaseFromJSON(_ json: JSON) -> PhaseResult {
        if let phase = Phase(json: json) {
            return .success(phase)
        } else {
            return .failure(PhaseModelError.noPhases)
        }
    }
    
    static func phasesFromJSON(_ json: JSON) -> PhasesResult {
        guard let data = json["response"] as? [JSON] else {
            return .failure(JSONError.badFormat)
        }
        
        let results = data.flatMap(Phase.phaseFromJSON)
        let phases = results.flatMap { (phase) -> Phase? in
            switch phase {
            case .success(let value):
                return value
            case .failure:
                return nil
            }
        }
        
        return .success(phases)
    }
}

The phaseFromJSON function is much like the moon counterpart; we find the name and time attribute and return a PhaseResult. The plural phasesFromJSON function is the new one, returning a PhasesResult. Here we dig into the response attribute and loop over the data, creating a new Phase for each object.

map applies a function to every element in a collection that transform the element into something different. In this case, we’re mapping over the JSON elements and transforming each into a PhaseResult. Following that, the filter function is used to filter out any PhaseResult that are empty. Finally, map is used once more to force-unwrap and return a Phase.

Instead of the above, we can use the flatMap function, which takes an array of optional somethings, and return only the real values. This is essentially what the filter function is doing above. Using flatMap, our phasesFromJSON function could be written as the following.

static func phasesFromJSON(json: JSON) -> PhasesResult {
    guard let data = json["response"] as? [JSON] else {
        return .Failure(JSONError.BadJSON)
    }
    
    let results = data.flatMap(Phase.phaseFromJSON)
    let phases = results.flatMap { (phase) -> Phase? in
        switch phase {
        case .Success(let value):
            return value
        case .Failure:
            return nil
        }
    }
    
    return .Success(phases)
}

From looking at the JSON response from the Aeris API, it’s important to note that the response contains an array. When creating a Moon, we dig into the response and find the first object, and then retrieve the moon attribute. When creating a set of Phases, we instead loop over the objects within the response array. The limit parameter we included returned multiple moon phases, corresponding the objects in the response array.

With the static generator function defined on our model objects, we can parse JSON returned from a network controller response.

Additional Resources

Several articles about handling JSON with Swift have appeared on the thoughtbot blog over the past months. Together the articles discuss the evolution of a JSON parsing approach that culminated with the creation of Argo. Read through the full series for the design rationale and techniques.

David Owens II wrote about and released a library called json-swift for working with JSON.

Responding to Change

So far we’ve built out the different layers of our app but they aren’t really communicating with each other yet. We haven’t discussed how information is flowing through the app, or how changes are communicated from one layer to another.

For example, the view controller needs to create view-models that reflect the current moon phase. How will the view controller know when the model has new data available?

There are several techniques for passing information back and forth between two objects or communicating events. It’s often mentioned that one should strive for a loose coupling and keep objects decoupled. Techniques like this are important because they help to isolate problems and keep responsibilities separate between different objects.

With Cocoa and Cocoa Touch, there are four main ways information is communicated: Delegation, Closures or Blocks, Key Value Observing, and sending notifications via NSNotificationCenter.

Technique Description
Delegation One object hands off responsibility of some tasks to another object that advertises it can perform the job(s).
Closures and Blocks Functions that capture their calling scope and are passed around as arguments into functions. The closure can be execute at a later point, after some event has occurred.
Notifications A message sent through a third-party channel that advertises the occurrence of some event.
Key Value Observing Properties on an object can be observed by another object, so that the observer is notified of when the value is changed.

We’ve already seen delegation with our table view and we’ve implemented aa callback system with our location tracker. Next we’ll look at Key Value Observing and Notifications and how they can be used to communicate changes.

Notifications

A notification has a unique name and may have a dictionary of information associated it with. Notifications usually represent the occurrence of some event, and they are named accordingly, such as UIApplicationDidEnterBackgroundNotification.

Notifications are broadcast to other objects using a notification center. To receive a notification, an object first registers with the notification center, announcing interest in receiving a particular notification. At some later point in time, the notification center broadcasts a notification to all interested parties that some event has occurred.

Beside the notification name, the objects sending and receiving notifications don’t need to know anything about each other.

We’ll design our model object to send out notifications when the lunar phase and forecast changes, or when any error occurs retrieving an update. The view controller will listen for these notifications and take the appropriate action, either updating the UI and reporting an error.

To create a notification we first need to define a notification name. Open the LunarPhaseModel and declare an extension at the top for the notifications we’re interested in. In this case, we’ll create two notifications for when the moon and phases update and one notification for when an error occurs.

extension Notification.Name {
    static let didUpdateMoon = Notification.Name("didUpdateMoon")
    static let didUpdatePhases = Notification.Name("didUpdatePhases")
    static let didReceiveLunarModelError = Notification.Name("didReceiveLunarModelError")
}

Next create two property observers for the moon and phases properties of the model object. A notification will be sent Whenever either the moon or phases property changes.

class LunarPhaseModel: NSObject {
    ...

    fileprivate var moon: Moon? {
        didSet {
            NotificationCenter.default.post(name: .didUpdateMoon, object: nil)
        }
    }
    
    fileprivate var phases: [Phase]? {
        didSet {
            NotificationCenter.default.post(name: .didUpdatePhases, object: nil)
        }
    }
}

Key Value Observing

Key Value Observation is a mechanism where one object can observe a property of another object. The observing object is notified every time an observed property changes. There’s a one way relationship between the two objects. Only the observing object needs to know about who to observe.

Apple describes KVO as a tool the controller can use to observe changes to model object properties. The controller has a reference to the model and observes property changes, while the model carries out its own job in isolation.

There are a few gotchas and issues the come along with using KVO.

  • KVO only works on NSObject subclasses. To use KVO from Swift, properties to be observed must be marked with dynamic modifier.
  • Observers are notified of any and all property changes through the observeValueForKeyPath method. This method can become unwieldy if an object observes several key-paths.
  • The context pointer that’s passed into observeValueForKeyPath is unintuitive and cumbersome, but ignoring it can cause unwanted side effects.

Apple discusses how to use Key Value Observing with Swift in Adopting Cocoa Design Patterns section of Using Swift with Cocoa and Objective-C

In our app, we’ll use KVO from the view controller to observe a boolean loading property on the model. As the loading state changes, the view controller will enable and disable the network status indicator.

Open up LunarPhaseModel and declare a boolean property named loading. In order the KVO to work, the property must be marked as dynamic.

class LunarPhaseModel: NSObject {
    ...

    dynamic var loading: Bool = false
}

Next move to the view controller and add it as an observer of the loading property in viewDidLoad. This is done using addObserver:forKeyPath:options:context:. The context is a pointer to random address that’s specific to your subclass, defined as an UnsafeMutablePointer. Create some constant to use as a context that private to your class, in this case called myContext.

To add the view controller as an observer, use the addObserver:forKeyPath:options:context method that is inherited from NSObject.

fileprivate let _context = UnsafeMutableRawPointer(bitPattern: 0)

class ViewController: UIViewController {
    ...
    
    override func viewDidLoad() {
        ...       
        
        self.model.addObserver(self, forKeyPath: "loading", options: .new, context: _context)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if self.model == object as? LunarPhaseModel && keyPath == "loading" && context == _context {
            UIApplication.shared.isNetworkActivityIndicatorVisible = self.model.loading
        }
        else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
    
}

It’s in the implementation of observeValue:forKeyPath: that things start to get interesting. To be thorough, we check if the keypath, object and context all match what we’re looking for. If all the values don’t match, it’s important to call the super implementation. If they do match we set the network activity indicator visibility from the loading property of the model.

Accessing the model state

Earlier we added private properties onto LunarPhaseModel for moon and phases, but we still need to create a public way for the model state to be accessed. This is a great place to use the Result type defined earlier.

typealias CurrentMoon = Result<Moon>
typealias CurrentPhases = Result<[Phase]>

Above we define two new types; the CurrentMoon type is a Result that contains a Moon while the CurrentPhases type is a Result that contains an array of Phase objects.

Define the PhaseModelError type to describe a model error. This type will handle errors fetching the moon and the current phases.

enum PhaseModelError: Error {
    case noMoon
    case noPhases
}

Next define two public properties on the LunarPhaseModel for accessing the current moon and phases. These properties will use the Result type and return success or failure using the shorthand notation.

class LunarPhaseModel: NSObject {
    ...

    var currentMoon: CurrentMoon {
        if let moon = self.moon {
            return .success(moon)
        }
        
        return .failure(PhaseModelError.noMoon)
    }
    
    var currentPhases: CurrentPhases {
        if let phases = self.phases {
            return .success(phases)
        }
        
        return .failure(PhaseModelError.noPhases)
    }
}

From the view controller, we can listen for notifications from the model to determine when the current moon or phases has changed. These notifications are set from the didSet override. The view controller should subscribe to the notifications in viewDidLoad and implement methods to handle them.

class ViewController: UIViewController {
    ...

    override func viewDidLoad() {
        super.viewDidLoad()
        
        ...
        
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.modelDidUpdate(_:)), name: .didUpdateMoon, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didReceiveError(_:)), name: .didReceiveLunarModelError, object: nil)
    }
    
    func didReceiveError(notification: NSNotification) -> Void {
        // TODO: handle error
    }
    
    func modelDidUpdate(notification: NSNotification) -> Void {
        self.updateLunarViewModel()
    }
    
    func updateLunarViewModel() -> Void {
        let result = self.model.currentMoon
        
        switch result {
        case .success(let moon):
            self.headerView.viewModel = LunarViewModel(moon: moon)
        case .failure:
            print("error updating view model, no data")
        }
    }
}

Swift Alternatives to KVO

Several alternatives to KVO have been suggested, each of which tries to take advantage of the of what Swift brings to the table. KVO has always been a clunky API to use in Objective-C and with the move to Swift, it doesn’t really fit nicely into the language. In the interest of keeping things simple, we didn’t explore any KVO alternatives in the app, but some of the solutions proposed are interesting and worth looking at.

For some background on why KVO isn’t ideal, see the aptly named KVO Considered Harmful article by Soroush Khanlou.

In Exploring KVO Alternatives in Swift, Scott Logic looks at few solutions for adding events to Swift, weighing the pros and cons and each.

Bond is a binding framework written in Swift and extensively detailed in the accompanying article Solving the binding problem with Swift.

Drawing Custom Views

Using the lunar symbols from the weather icons font works well enough for showing an image of the moon, but there are other solutions. Instead of using an icon font, we can attempt to draw the moon phase by hand using Core Graphics.

Core Graphics or Quartz is a 2D drawing API available as part of the Cocoa framework. Using Core Graphics, you can create paths and shapes, manage layers, handle text rendering, and create PDFs (plus much more).

Shapes are created from Bézier curves using instances of UIBezierPath. Bézier curves really powerful and can be used to define any shape. There’s an awesome interactive Primer on Bézier Curves put together by Mike Kamermans that really gets into the math behind them. Even if you’re not a math geek, you should still check out the site’s interactive graphics and get a feel for how control points work.

The math necessary to define an exact path for the moon is complex, but we don’t have to do this ourselves. In Calculate and Draw Moon Phase, Mostafa Kaisoun presents a Visual Basic and C# solution that draws the moon from the current day. It’s only specific enough for a day, not time, but this accurate enough for our needs. Both the illuminated and shadow portions of the moon are drawn. By adapting the solution to use Core Graphics, we’ll be able to create a custom UIView that draws the moon phase from an NSDate.

Subclassing UIView

Begin by creating a new subclass of UIView. The view will have a date property that can either be set via a custom initializer or will default to the current date. Because we override initWithFrame: we also need to override initWithCoder:. Setting the background color to clear will allow the containing view to show through.

class LunarPhaseView: UIView {
    let date: Date
    
    init(frame: CGRect, date: Date) {
        self.date = date
        super.init(frame: frame)
        
        self.backgroundColor = UIColor.clear
    }
    
    override init(frame: CGRect) {
        self.date = Date()
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        self.date = Date()
        super.init(coder: aDecoder)
    }
    
    override func draw(_ rect: CGRect) {
    	// TODO: implement
    }
}   

Before getting to far along, let’s provide a stub draw:rect implementation and make sure the LunarPhaseView can be hooked into the LunarHeaderView. In the stub implementation, the moon will be represented by a red circle.

override func draw(_ rect: CGRect) {
    let path = UIBezierPath(ovalIn: rect)
    UIColor.red.setStroke()
        
    path.stroke()
}

The draw:rect method is passed a rectangular region to draw into. This CGRect corresponds to the size of the view in the implementing subclass. We can take the rectangle directly and define an oval shaped UIBezierPath from it. Once the path is setup, we define a stroke color used to color or draw the path. Finally, we draw the path using the stroke() method.

Next add the phase view into the header view, replacing the UILabel with our custom subclass. Delete the phaseLabel currently used to show the lunar icon, and drag out a UIView from the object library. The exact position and size of the view doesn’t matter but it should be square. If the view is square, the oval path defined later will be circular. This is what we want for depicting the moon.

One key step is to change class from UIView to LunarPhaseView. This creates an instance of our custom subclass inside the nib.

If everything is connected correctly, a red circle should be shown in the header view when the app is run. However, we don’t necessary have to run the app to see the changes. Starting in iOS 8, custom views annotated with @IBDesignable will render inside a nib or storyboard, with no need to run the app. Add @IBDesignable annotation before the subclass is definition.

@IBDesignable
class LunarPhaseView: UIView {
	...
}

With @IBDesignable, Interface builder will initialize your view using initWithFrame: and render the view directly inside the nib or storyboard file.

Red Circle Drawn

Drawing the visible Moon

The moon phase drawing example referenced earlier uses two helper methods for finding the moon age and julian date. Afterwards, the DrawMoon functions uses the moon age value to find the paths the draw.

We can define an extension on NSDate that converts to Julian Day and returns the current Moon phase age, represented as a Double. The math for Julian date conversion is done in the C# example but there’s some Swift code available too.

import Foundation

extension Date {
    
    fileprivate var epochJulianDate: Double {
        return 2440587.500000
    }
    
    fileprivate var lunarSynodicPeriod: Double {
        return 29.53059
    }
    
    fileprivate var julianDate: Double {
        return epochJulianDate + timeIntervalSince1970 / 86400
    }
    
    var moonPhase: Double {
        let jd = julianDate
        let phase = (jd + 4.867) / lunarSynodicPeriod
        return (phase - floor(phase))
    }
}

The only exposed method is moonPhase() which uses the Julian day and lunar synodic period to determine the phage, and returns a Double. This code is almost a direct port of the C# example. In this case, page coo responds to the number of days old the current lunar cycle is.

With the date to moon age conversion in place, we can turn our attention back to the drawing. The algorithm presented in the C# example uses line-by-line approach, where the light and dark portions of the moon are assembled from horizontal lines stack on top of each. This is similar to the raster scan a CRT performs when drawing pictures.

class LunarPhaseView: UIView {
    ...

    override func draw(_ rect: CGRect) {
        let phase = self.date.moonPhase
        let diameter = Double(rect.width)
        let radius = Int(diameter / 2)
        
        for Ypos in 0...radius {
            let Xpos = sqrt(Double((radius * radius) - Ypos*Ypos))
            
            let pB1 = CGPoint(x: CGFloat(Double(radius)-Xpos), y: CGFloat(Double(Ypos)+Double(radius)))
            let pB2 = CGPoint(x: CGFloat(Xpos+Double(radius)), y: CGFloat(Double(Ypos)+Double(radius)))
            
            let pB3 = CGPoint(x: CGFloat(Double(radius)-Xpos), y: CGFloat(Double(radius)-Double(Ypos)))
            let pB4 = CGPoint(x: CGFloat(Xpos+Double(radius)), y: CGFloat(Double(radius)-Double(Ypos)))
            
            let path = UIBezierPath()
            path.move(to: pB1)
            path.addLine(to: pB2)
            
            path.move(to: pB3)
            path.addLine(to: pB4)
            
            UIColor.black.setStroke()
            path.stroke()
            
            let Rpos = 2 * Xpos
            var Xpos1 = 0.0
            var Xpos2 = 0.0
            if (phase < 0.5) {
                Xpos1 = Xpos * -1
                Xpos2 = Double(Rpos) - (2.0 * phase * Double(Rpos)) - Double(Xpos)
            }
            else {
                Xpos1 = Xpos;
                Xpos2 = Double(Xpos) - (2.0 * phase * Double(Rpos)) + Double(Rpos)
            }
            
            let pW1 = CGPoint(x: CGFloat(Xpos1+Double(radius)), y: CGFloat(Double(radius)-Double(Ypos)))
            let pW2 = CGPoint(x: CGFloat(Xpos2+Double(radius)), y: CGFloat(Double(radius)-Double(Ypos)))
            let pW3 = CGPoint(x: CGFloat(Xpos1+Double(radius)), y: CGFloat(Double(Ypos)+Double(radius)))
            let pW4 = CGPoint(x: CGFloat(Xpos2+Double(radius)), y: CGFloat(Double(Ypos)+Double(radius)))
            
            let path2 = UIBezierPath()
            path2.move(to: pW1)
            path2.addLine(to: pW2)
            
            path2.move(to: pW3)
            path2.addLine(to: pW4)
            
            UIColor.white.setStroke()
            path2.lineWidth = 2.0
            path2.stroke()
        }
    }
}

With that, the moon phase view should render inside the storyboard.

Lunar phase view

Testing

Testing is the act of ensuring things work as expected. It’s a setup of steps taken and actions performed that guarantee one set of inputs produces the same output. There are many different types of tests and ways of testing. One of the more common techniques is unit testing. We’ll focus on writing unit tests using the XCTest framework.

Not everyone practices TDD so ending up with a mostly complete app and no tests is not uncommon. Some environments require a more rigorous level of testing than others, such as applications in the Health and Medical field.

Sometimes it seems that deciding what to test is half the problem. The short answer is that you should test everything you deem important. Ideally each class should have a test class associated with it.

Mocks and Dependency Injection

Mock objects substitute real objects and replicate their behavior. They can be used in place of real object, when creating a real object isn’t possible. Mock objects allow some set of behaviors to be fakes while another set is tested.

Creating mocks objects in Swift is much easier because Swift allows classes to be declared inside other classes or functions. This makes it possible to subclass an object and mock behavior by overriding methods.

By designing objects to support Dependency Injection, behaviors can be changed by passing in or injecting a different dependency. By Using mock objects to stand in for another objects dependencies, and injecting the mocks on creation, difficult and complex system may be more easily tested.

Swift allows default function parameter values to be specified in the declaration, making for an elegant way to support change dependency. As an example, consider the LocationTracker created earlier. Testing is difficult because of the private, internal CLLocationManager instance that the LocationTracker wraps. By modifying the init function and adding a default parameter value, we’ll be able to inject a fake CLLocationManager during testing.

public class LocationTracker: NSObject, CLLocationManagerDelegate {

    private let locationManager: CLLocationManager
    
    init(locationManager: CLLocationManager = CLLocationManager()) {
        self.locationManager = locationManager
        super.init()
        
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestWhenInUseAuthorization()
        
        ...
    }

    ...
}

The location manager can be mocked and injected into the LocationTracker during tests. The fake location manager is configured to call the delegate methods with a dummy location, simulating a location change.

func testLocationUpdateIsPublished() {
    let fakeLocationManager = FakeLocationManager { (manager) -> Void in
        let location = CLLocation(latitude: 25.7877, longitude: -80.2241)
        manager.delegate?.locationManager?(manager, didUpdateLocations: [location])
    }
    
    let locationTracker = LocationTracker(locationManager: fakeLocationManager)

    // test location tracker
}

General Recipe

For each class and struct under test, the following steps can be taken.

  1. Select a class or struct to write tests for.
  2. Create a new subclass of XCTestCase and name it after the entity under test.
  3. Identify what core functionality will be tested.
  4. Define what a success test is.
  5. Build the test harness infrastructure and setup preconditions.
  6. Run the test and verify the result.

Testing the Model

To test the model objects, we’ll verify that correct model objects are created from JSON files representing sample responses. The JSON files will be added to the project as part of the unit test target. It’s not uncommon to have local test file

Using a tool like cURL or HTTPie, capture JSON responses from the /sunmoon and /sunmoon/moonphases endpoints and save them locally. The location used when querying the API doesn’t really matter; we’re only interested in the response. With the JSON saved, we can move onto defining tests for the Moon and Phase objects.

Create a subclass of XCTestCase called MoonTests. By default, it will be added as a member of the unit test target, and not the application target. This is what we want because MoonTests won’t be part of the finish app; it’s only used of for testing app functionality.

The name of subclass can be anything, but it’s common to name the test case after the class under test, by appending the Tests suffix. The new subclass will contain some example tests already written. These functions are named with a test prefix, and this is important. In a XCTestCase subclass, a function with the test prefix is considered a test, such as testDoesRespondToUpdate or testWillPostNotification.

You’ll also notice a setUp and tearDown function.

Start by defining a test case that fails all the time, using XCTFail. You can leave the failing test around as a reminder to implement it later. This can be helpful when you know you need to test something but the implementation behind the scenes isn’t fleshed out.

class MoonTests: XCTestCase {
    
    func testMoonIsCreatedFromJSON() {
        XCTFail("Not Implemented")
    }
}

To run the unit test target, select Product > Test inside Xcode or use the ⌘U shortcut. Test output will appear on the console. Passing and failing tests are indicated by green and red icons. You should see one failing test. Next we’ll make it pass.

To test that Moon object is created, we’ll load the sample response into an Data object, convert it to JSON using NSJSONSerialization. Then we’ll call moonFromJSON and verify the Moon object return matches the JSON passed in.

class MoonTests: XCTestCase {

    func testMoonIsCreatedFromJSON() {
        let file = Bundle(for: type(of: self)).url(forResource: "sunmoon", withExtension: "json")
        
        do {
            let data = try Data(contentsOf: file!)
            let json = try data.toJSON()
            guard let moon = Moon(json: json) else { return XCTFail("Could not create moon") }
            
            XCTAssertEqual(moon.phase, "waning crescent", "Moon phase is incorrect")
            XCTAssertEqual(moon.age, 24.02, "Moon age is incorrect")
            XCTAssertEqual(moon.illumination, 31, "Moon illumination is incorrect")
            XCTAssertEqual(moon.percent, 0.81340000000000001, "Moon percent is incorrect")
        }
        catch {
            XCTFail("Failing JSONResult was found")
        }
    }
}

The trick is loading the sample JSON response correctly. Because the JSON file is in the unit test target and not the app target, it won’t be available in the main bundle, so we cannot use Bundle.main to find the resource path. Instead we must retrieve the bundle for this class, using Bundle(for: AnyClass). Here the class passed in is the type of the current class and not the string name.

Testing the View-Model

Testing the view-model is a little more straight forward than the model, because we can create model objects directly instead of loading from JSON. Because the model layer has already been tested, we don’t need to retest it again by recreating objects from JSON. We can initialize them by hand and pass them directly into the view-model.

A view-model test should ensure that a model object can be properly represented for a view. In our case, this means that the view-model can format the lunar phase, age and percent into a strings for the view.

class LunarViewModelTests: XCTestCase {
    
    var viewModel: LunarViewModel {
        let moon = Moon("waning crescent", 24.02, 0.8134, 31, Date(), Date())
        let viewModel = LunarViewModel(moon: moon)
        return viewModel
    }
}

Testing Network requests using custom URL Protocols

Hitting the network from a unit test is never a good idea. The tests are design to be run often and should perform in isolation, without the need of a network.

By creating subclasses of URLProtocol, we can mimic the different responses from API endpoints. We’ll do this by configuring an URLSessionConfiguration for our custom protocol. The configuration will then be injected into the network controller on initialization. This will allow us create a fake API for the unit tests.

To begin with, we’ll look at creating a protocol to mimic failed responses from the server. Start by creating a new subclass of URLProtocol in the unit test target.

class FailingURLProtocol: URLProtocol {
    
    override class func canInit(with request: URLRequest) -> Bool {
        return true
    }
    
    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        return request
    }
    
    override func startLoading() {
        // TODO: implement
    }
    
    override func stopLoading() {
        // all data return at once, nothing to do
    }
}

Next implement the startLoading function. Below we create a HTTPURLResponse with a 404 NOT FOUND status code representing a failed request. The delegate methods are called on the client, mimicking the flow of a real response. A custom Error is also created and passed along inside URLProtocol:didFailWithError:. It’s important to conclude by calling URLProtocolDidFinishLoading and finish the request.

class FailingURLProtocol: URLProtocol {
    ...

    override func startLoading() {
        guard let client = self.client else { fatalError("Client is missing") }
        guard let url = request.url else { fatalError("URL is missing") }
        
        let error = NSError(domain: "org.andyshep.Luna", code: 404, userInfo: nil)
        guard let response = HTTPURLResponse(url: url, statusCode: 404, httpVersion: "HTTP/1.1", headerFields: [:]) else {
            fatalError("Response could not be created")
        }
        
        client.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
        client.urlProtocol(self, didFailWithError: error)
        client.urlProtocolDidFinishLoading(self)
    }
}

To use the custom protocol, configure a new URLSessionConfiguration with it. An ephemeral session configuration is used so that no data is stored to disk.

extension URLSessionConfiguration {
    class func configurationWithProtocol(_ protocolClass: AnyClass) -> URLSessionConfiguration {
        let protocolClasses: [AnyClass]? = [protocolClass]
        
        let configuration = URLSessionConfiguration.ephemeral
        configuration.protocolClasses = protocolClasses
        
        return configuration
    }
}

Next create a networking controller with the new configuration.

let configuration = URLSessionConfiguration.configurationWithProtocol(FailingURLProtocol.self)
let networkController = NetworkController(configuration: configuration)

Asynchronous Testing, Setting Expectations

Network requests are made asynchronously. The response is not returned immediately, and the calling thread continues to execute while the request is handled. When testing a network request, we want to fire off a request, “wait around” until the response is returned, and then verify the result.

Using XCTestExpectation we can state some conditions we expect to meet and then wait around for them to occur. Using a fulfill method on the expectation, we can determine when the conditions are met at a later point in time. Consider the following example from the NetworkControllerTests.

class NetworkControllerTests: XCTestCase {
    
    var location: Location {
        let coordinate = CLLocation(latitude: 25.7877, longitude: -80.2241)
        let location = Location(location: coordinate, city: "Miami", state: "FL", neighborhood: "")
        return location
    }

    func testCanRequestMoonSuccessfully() {
        let expected = expectation(description: "Request should be successful")
        let configuration = URLSessionConfiguration.configurationWithProtocol(LocalURLProtocol.self)
        let networkController = NetworkController(configuration: configuration)
        
        let request = AerisAPI.moon(location.physical).request
        
        networkController.start(request, result: { (result) -> Void in
            switch result {
            case .success:
                expected.fulfill()
            case .failure:
                XCTFail("Request should not fail")
            }
        })
        
        waitForExpectations(timeout: timeout, handler: nil)
    }
}

First an expectation is creating with some description. This is a statement about some event we expect to occur; what we’re testing or what we’re interested in. Next a URLSessionConfiguration is created a local URL protocol, setup to return local JSON and fake the network responses. Using a NetworkController created with the configuration, a request is made for current Moon phase.

While the request is pending, the calling thread continues until the waitForExpectations:with: function is hit. At that point it waits around for some duration for duration until the expectations are fulfilled. The request is later returned on another thread. If it was successful the expectation is fulfilled.

Additional Resources

The objc.io periodical devoted issue #15 to Testing. See the article on Dependency Injection by Jon Reid.

Natasha The Robot has written some great articles about Swift, including one about dependency injection.

If you’re interested in a Swift framework for testing, check out Quick or listen to one of the talks given about it.

Next Steps

Congratulations! If you’ve made it this far, you should have a functional app and a solid understanding of the design concepts behind it. More importantly, you’re ready to move on and continue exploring Cocoa.

In some ways, this app is intentionally simple. Other apps might require multiple screens or view controllers, segues or transitions, data persistence, capturing user input, accessing the camera or playing media.

So there’s much more to explore. The internet is rich with resources, so until next time, here’s a few places to continue exploring on your own.

Change Log

November 2015

  • Removed Box wrapper class; no longer needed with Swift 2
  • Changed JSON parsing to use guard statements

January 2016

  • Updated Result type to use ErrorType from the standard library

March 2016

  • Replaced stringly typed selector names with #selector expressions

September 2016

  • Refactored method and class names for Swift 3