Creating Interactive Notifications in iOS 8

Creating Notification Actions

Several times up to this point I talked about notification actions, but always generally speaking. Now, it’s time to see what they really are.

An action is an object of the UIMutableUserNotificationAction class. This class is new in iOS 8, and provides various useful properties so an action can be properly configured. These are:

  • identifier: This is a string value, that uniquely identifies an action among all in an application. Obviously, you should never define two or more actions with the same identifier. Also, using this property we’ll be able to determine the chosen action by the user upon the notification appearance. We’ll see that later.
  • title: The title is the text that is shown on the action button to the user. This can be either a simple, or a localized string. Be cautious and always set proper titles to your actions, so the user can instantly understand by reading the 1-2 title words what is going to happen by selecting it.
  • destructive: This is a bool value. When it is set to true the respective button in the notification has red background colour. Note that this happens in the banner mode only. Usually, actions regarding deletion, removal and anything else critical are marked as destructive, so they increase the user’s attention.
  • authenticationRequired: This property is a bool value also. When it becomes true, the user must necessarily authenticate himself to the device before the action is performed. It’s extremely useful in cases where the action is critical enough, and any unauthorised access can damage the application’s data.
  • activationMode: This is an enum property, and defines whether the app should run in the foreground or in the background when the action is performed. The possible values specifying each mode are two: (a) UIUserNotificationActivationModeForeground, and (b) UIUserNotificationActivationModeBackground. In background, the app is given just a few seconds to perform the action.

While I was describing this demo application, I said that we’re going to create three distinct actions:

  1. An action to just make the notification go away, without anything else to be performed.
  2. An action to edit the list (actually to add a new item).
  3. An action to delete the entire list.

Let’s see how each one is written in code. For every action, we will set the values to all the aforementioned properties. The first one:

The identifier of this action is “justInform”. As you see, this action will be performed in the background, and as there’s nothing dangerous with it we set to false the destructive and the authenticationRequired properties.

The next one:

Apparently, this action requires the app to run in the foreground so we can edit the shopping list. Also, we don’t want nobody else to mess with our list, so we set the authenticationRequired to true.

And the third and last one:

With this action we’ll allow the user to delete the entire shopping list without launching the application in the foreground. However, this is a dangerous action for the data, therefore we tell the app that it’s destructive and that authentication is required to proceed.

By looking at the above actions setup, you understand that configuring them is an easy task.

Now that we have done all the above, let’s add them to the setupNotificationSettings function we started to implement in the previous part:

Action Categories

When the actions of a notification have been defined, they can then be grouped together in categories. Actually, categories are what is written in the settings, and not the actions themselves, so you should always create them, unless of course you present a notification without actions. Usually, a category matches to a notification, so supposing that all notifications in an application support actions, there should be as many categories as the notifications.

In this demo application, we are going to create just one notification, so we are going to have one category only. Programmatically speaking now, a category is an object of the UIMutableUserNotificationCategory class, which is also new in iOS 8. This class has just one property and one method. The property is a string identifier that uniquely identifies a category (similarly to actions), and the method is used to group the actions together.

Let’s see a few more things about that method, and let’s start by its signature (taken by the Apple documentation directly):

The first parameter regards the actions that should be grouped for the category. It’s an array containing all the actions, and the order of the of the action objects in the array specifies the order they will appear in the notification.

The second parameter is quite important. The context is an enum type, and describes the context of the alert that the notification will appear into. There are two possible values:

  1. UIUserNotificationActionContextDefault: It matches to a full alert that is appeared to the centre of the screen (when the device is unlocked).
  2. UIUserNotificationActionContextMinimal: It matches to a banner alert.

In the default context, the category can accept up to four actions, which will be displayed in the predefined order in the notification alert (at the screen centre). In the minimal context, up to two actions can be set to appear in the banner alert. Notice that in the second case, you must choose what the most important actions are among all so they appear in the banner notification. In our implementation we’ll specify the actions for both contexts.

As I said, the first parameter in the above method must be an array. For this reason, our initial step is to create two arrays with the actions for each context. Let’s go back to our function:

Next, let’s create a new category for which we will set an identifier, and then we will provide the above arrays for the two contexts:

And… that’s all it takes to create a category regarding the actions of a notification.

Registering Notification Settings

In the last three parts we configured all the new features of the local notification, and now we have only left to write everything to settings. For this purpose, we will use the UIUserNotificationSettings class (new in iOS 8), and through the following init method we’ll provide the types and the category of the notification:

The first parameter is the types we defined for the notification. The second parameter is a NSSet object, in which all the categories for all the existing notifications in an application must be set. In this example, we have just one category, however we’ll create a NSSet object no matter what.

Let’s continue the function implementation with that:

Now, we can create a new object of the UIUserNotificationSettings class and pass the required arguments:

Lastly, let’s write (register) the settings in the Settings app using the next line:

The first time the above code will work, it will create a new record for our application in the Settings app.

Now, before I present you the whole setupNotificationSettings() after all the previous additions, let me say something more. This function will be called in the viewDidLoad method, and that means that its content will be executed every time the app runs. However, as the notification settings are not going to change and therefore it’s pointless to set them again and again, it would be wise to contain all the above code in an if statement. In the condition of this statement, we will check if the notification types have been specified or not, where in the second case the if body will be executed. This is translated to code as shown next:

At first, we get the existing notification settings using the currentUserNotificationSettings() method of the UIApplication class. This method returns a settings object, through which we can check the current value of the types property. Remember that this property is an enum type. If its value equals to None, meaning that no notification types have been set, then we’ll allow it to register the notification settings by doing all the above in the previous parts, otherwise will do nothing.

With the above condition we avoid unneeded settings registration. Note though that if you want to modify any settings or add more actions, categories, etc for new notifications, you should comment out the if opening and closing lines and run the app once, so the new additions to be applied and so you can test it with the new settings. Then, remove the comments to revert your code to its previous state.

With that, all the work in the notification details is over. Right next you can see the setupNotificationSettings() function fully implemented and in one part:

Don’t forget to call this function in the viewDidLoad body:

Handling Notification Actions

There is one last aspect of the local notification that we haven’t worked with yet, and that is to handle the actions that get received by the application when the user taps on the respective buttons. As usual, there are certain delegate methods that should be implemented.

Before we see what actions we’ll handle and how, let me introduce you a couple of other delegate methods that can become handy when developing your own applications. Note that in this demo we won’t really use them; we’ll just print a message to the console. Also, make sure to open the AppDelegate.swift file now.

So, the first one regards the notification settings. This delegate method is called when the app is launched (either normally or due to a local notification’s action) and contains all the settings configured for the notifications of your app. Right next you can see its definition. What we only do, is to print the current notification types:

Regardless of the above simple implementation, you can use it to access all kind of settings supported by the UIUserNotificationSettings class. This method can become useful in cases you need to check the existing settings and act depending on the values that will come up. Don’t forget that users can change these settings through the Settings app, so do never be confident that the initial configuration made in code is always valid.

When scheduling a local notification, this will be fired no matter whether your application is currently running or not. Usually, developers imagine how the notifications are going to appear when the app is in the background or suspended, and all the implementation is focused on that. However, it’s your duty to handle a notification in case it will be fired when the app is running. Thankfully, iOS SKD makes things pretty straightforward, as there’s another delegate method that is called when the app is in the foreground:

There will be cases where you won’t need to handle the notification if your app is running. However, in the opposite scenario, the above method is the place to deal with it and perform the proper actions.

Now let’s focus on the delegate method that is called when an action button is tapped by the user. Based on the identifier values we set to the actions, we’ll determine which one has been performed, and then we will make the app execute the proper part of code. We configured three actions in total:

  1. One to make the notification simply go away (identifier: justInform).
  2. One to add a new item to the list (identifier: editList).
  3. One to delete entire the list (identifier: trashAction).

From all the above, we don’t need to do anything when the first action is performed. However, we’ll handle the other two. Depending on the identifier value, we will post a notification (NSNotification) for each one, and then in the ViewController class we’ll observe for those notifications, and of course, we’ll handle them.

Let’s get started with the new delegate method:

In both cases we post a notification (a NSNotification), specifying a different name each time. Notice that at the end we call the completion handler, and that’s mandatory to do, so the system knows we handled the received action. This is the most important delegate method when working with local notifications, as this is the place where you’ll route your code depending on the action the user performed.

Now, let’s go back to the ViewController.swift file. There, let’s make that class observe for the notifications we set before. In the viewDidLoad method add the next lines:

The modifyListNotification() and deleteListNotification() are both custom functions that we’ll implement right next.

Let’s begin with the first one. What we want is to make the textfield the first responder when the app is launched due to the edit list action, so we’re just talking about one line of code only:

With this, the keyboard will automatically be shown and the user will be able to type a new item immediately.

For the delete list action, we want to remove all existing objects from the array that contains them. So, we’ll do exactly that, and then we’ll save the (empty) array back to file. Lastly, we’ll reload the tableview data, so when the user launches the app will find no items at all:

With the above implemented, our demo application is finally ready!

Advertisements
Creating Interactive Notifications in iOS 8

Creating iOS Frameworks

Have you ever wanted to share a chunk of code between two or more of your apps, or wanted to share a part of your program with other developers?

Maybe you wanted to modularize your code similarly to how the iOS SDK separates its API by functionality, or perhaps you want to distribute your code in the same way as popular 3rd parties do.

In this iOS frameworks tutorial you’ll learn how to do all of the above!

In iOS 8 and Xcode 6, Apple provided a new template, Cocoa Touch Framework. As you’ll see, it makes creating custom frameworks much easier than before.

Frameworks have three major purposes:

  • Code encapsulation
  • Code modularity
  • Code reuse

You can share your framework with your other apps, team members, or the iOS community. When combined with Swift’s access control, frameworks help define strong, testable interfaces between code modules.

In Swift parlance, a module is a compiled group of code that is distributed together. A framework is one type of module, and an app is another example.

In this iOS frameworks tutorial, you’ll extract a piece of an existing app and set it free, and by doing so, you’ll learn the ins and outs of frameworks by:

  • Creating a new framework for the rings widget
  • Migrating the existing code and tests
  • Importing the whole thing back into the app.
  • Packing it up as an uber-portable CocoaPods
  • Bonus: Setting up a repository for your framework

By the time you’re done, the app will behave exactly as it did before, but it will use the portable framework you developed! :]

Getting Started

Download the Phonercise Starter Project.

Phonercise is a simple application that replicates the Apple Watch Activity app, except it measures your phone’s physical activity. The three rings on the main view represent movement, standing and exercise.

To get the most out of the project, you’ll need to build and run on an actual iOS device, and turn on the volume. Go ahead now, build and run!

Move the phone around to get credit for movement, and “exercise” the phone by shaking it vigorously — that’ll get its heartrate up. To get credit for standing up, just hold the phone upright.

The logic for the app is pretty simple:

  • ActionViewController.swift contains the view lifecycle and motion logic.
  • All the view logic is in the files in the Three Ring View folder, where you’ll find ThreeRingView.swift, which handles the view, and Fanfare.swift, which handles the audio. The other files handle the custom drawing of the shading, gradient and shapes.

The ring controls are pretty sweet. They’ve got an addictive quality and they’re easy to understand. Wouldn’t it be nice to use them in a number of applications beyond this fun, but completely silly app? Frameworks to the rescue!

Creating a Framework

Frameworks are self-contained, reusable chunks of code and resources that you can import into any number of apps and even share across iOS, tvOS, watchOS, and macOS apps.

If you’ve programmed in other languages, you may have heard of node modules, packages, gems, jars, etc. Frameworks are the Xcode version of these. Some examples of common frameworks in the iOS SDK are: Foundation, UIKit, AVFoundation, CloudKit, etc.

Framework Set Up

In Xcode 6, Apple introduced the Cocoa Touch Framework template along with access control, so creating frameworks has never been easier. The first thing to do is to create the project for the framework.

    1. Create a new project. In Xcode, go to File/New/Project.
    2. Choose iOS/Framework & Library/Cocoa Touch Framework to create a new framework.
  1. Click Next.
  2. Set the Product Name to ThreeRingControl. Use your own Organization Name and Organization Identifier. Check Include Unit Tests. That’s right! You’re going to have automated tests ensure your framework is bug free
  3. Click Next.
  4. In the file chooser, choose to create the project at the same level as the Phonercise project.
  5. Click Create.

Now you have a project (albeit a boring one) that creates a framework!

Add Code and Resources

Your current state is a framework without code, and that is about as appealing as straight chocolate without sugar. In this section, you’ll put the pod in CocoaPods by adding the existing files to the framework.

From the Phonercise source directory, drag the following eight files into the ThreeRingControl project in Xcode:

  • CircularGradient.swift
  • coin07.mp3
  • Fanfare.swift
  • RingLayer.swift
  • RingTip.swift
  • ThreeRingView.swift
  • Utilities.swift
  • winning.mp3

Make sure to check Copy items if needed, so that the files actually copy into the new project instead of just adding a reference. Frameworks need their own code, not references, to be independent.

Double-check that each of the files has Target Membership in ThreeRingControl to make sure they appear in the final framework. You can see this in the File Inspector for each file.

Build the framework project to make sure that you get Build Succeeded with no build warnings or errors.

Add the Framework to the Project

Close the ThreeRingControl project, and go back to the Phonercise project. Delete the six files under the Three Ring View group as well as the two MP3 files in Helper Files. Select Move to Trash in the confirmation dialog.

Build the project, and you’ll see several predictable errors where Xcode complains about not knowing what the heck a ThreeRingView is. Well, you’ll actually see messages along the lines of “Use of undeclared type 'ThreeRingView'“, among others.

Adding the Three Ring Control framework project to the workspace is the solution to these problems.

Add the Framework to the Project

Right-click on the root Phonercise node in the project navigator. Click Add Files to “Phonercise”. In the file chooser, navigate to and select ThreeRingControl.xcodeproj. This will add ThreeRingControl.xcodeproj as a sub-project.

Note: It isn’t strictly necessary to add the framework project to the app project; you could just add the ThreeRingControl.framework output.

However, combining the projects makes it easier to develop both the framework and app simultaneously. Any changes you make to the framework project are automatically propagated up to the app. It also makes it easier for Xcode to resolve the paths and know when to rebuild the project.

Even though the two projects are now together in the workspace, Phonercise still doesn’t get ThreeRingControl. It’s like they’re sitting in the same room, but Phonercise can’t see the new framework.

Try linking the framework to the app’s target to fix this problem. First, expand the ThreeRingControl project to see the Products folder, and then look for for ThreeRingControl.framework beneath it. This file is the output of the framework project that packages up the binary code, headers, resources and metadata.

Select the top level Phonercise node to open the project editor. Click the Phonercise target, and then go to the General tab.

Scroll down to the Embedded Binaries section. Drag ThreeRingControl.framework from the Products folder of ThreeRingControl.xcodeproj onto this section.

You just added an entry for the framework in both Embedded Binaries and Linked Frameworks and Binaries.

Now the app knows about the framework and where to find it, so that should be enough, right?

Build the Phonercise project. More of the same errors.

Access Control

Your problem is that although the framework is part of the project, the project’s code doesn’t know about it — out of sight, out of mind.

Go to ActionViewController.swift, and add the following line to the list of imports at the top of the file.

import ThreeRingControl

It’s critical, but this inclusion won’t fix the build errors. This is because Swift uses access control to let you determine whether constructs are visible to other files or modules.

By default, Swift makes everything internal or visible only within its own module.

To restore functionality to the app, you have to update the access control on two Phonercise classes.

Although it’s a bit tedious, the process of updating access control improves modularity by hiding code not meant to appear outside the framework. You do this by leaving certain functions with no access modifier, or by explicitly declaring them internal.

Swift has three levels of access control. Use the following rules of thumb when creating your own frameworks:

  • Public: for code called by the app or other frameworks, e.g., a custom view.
  • Internal: for code used between functions and classes within the framework, e.g., custom layers in that view.
  • Fileprivate: for code used within a single file, e.g., a helper function that computes layout heights.
  • Private: for code used within an enclosing declaration, such as a single class block. Private code will not be visible to other blocks, such as extensions of that class, even in the same file, e.g., private variables, setters, or helper sub-functions.

Ultimately, making frameworks is so much easier than in the past, thanks to the new Cocoa Touch Framework template. Apple provided both of these in Xcode 6 and iOS 8.

Update the Code

When ThreeRingView.swift was part of the Phonercise app, internal access wasn’t a problem. Now that it’s in a separate module, it must be made public for the app to use it. The same is true of the code in Fanfare.swift.

Open ThreeRingView.swift inside of ThreeRingControlProject.

Make the class public by adding the public keyword to the class definition, like so:

public class ThreeRingView : UIView {

ThreeRingView will now be visible to any app file that imports the ThreeRingControl framework.

Add the public keyword to:

  • Both init functions
  • The variables RingCompletedNotification, AllRingsCompletedNotification, layoutSubviews()
  • Everything marked @IBInspectable — there will be nine of these

Note: You might wonder why you have to declare inits as public. Apple explains this and other finer points of access control in their Access Control Documentation.

The next step is to do essentially the same thing as you did for ThreeRingView.swift, and add the public keyword to the appropriate parts of Fanfare.swift. For your convenience, this is already done.

Note that the following variables are public: ringSound, allRingSound, and sharedInstance. The function playSoundsWhenReady() is public as well.

Now build and run. The good news is that the errors are gone, and the bad news is that you’ve got a big, white square. Not a ring in sight. Oh no! What’s going on?

Update the Storyboard

When using storyboards, references to custom classes need to have both the class name and module set in the Identity Inspector. At the time of this storyboard’s creation, ThreeRingView was in the app’s module, but now it’s in the framework.

Update the storyboard, as explained below, by telling it where to find the custom view; this will get rid of the white square.

  1. Open Main.Storyboard in the Phonercise project.
  2. Select the Ring Control in the view hierarchy.
  3. In the Identity Inspector, under Custom Class, change the Module to ThreeRingControl.

Once you set the module, Interface Builder should update and show the control in the editor area.

Build and run. Now you’ll get some rings.

Creating iOS Frameworks

iOS Architecture Patterns

Feeling weird while doing MVC in iOS? Have doubts about switching to MVVM? Heard about VIPER, but not sure if it worth it?

Keep reading, and you will find answers to questions above, if you don’t — feel free to complain in comments.

You are about to structure your knowledge about architectural patterns in iOS environment. We’ll briefly review some popular ones and compare them in theory and practice going over a few tiny examples. Follow links if you need more details about any particular one.

Mastering design patterns might be addictive, so beware: you might end up asking yourself more questions now than before reading this article, like these:

Who supposed to own networking request: a Model or a Controller?

How do I pass a Model into a View Model of a new View?

Who creates a new VIPER module: Router or Presenter?

Why care about choosing the architecture?

Because if you don’t, one day, debugging a huge class with dozens different things, you’ll find yourself being unable to find and fix any bugs in your class.”. Naturally, it is hard to keep this class in mind as whole entity, thus, you’ll always be missing some important details. If you are already in this situation with your application, it is very likely that:

  • This class is the UIViewController subclass.
  • Your data stored directly in the UIViewController
  • Your UIViews do almost nothing
  • The Model is a dumb data structure
  • Your Unit Tests cover nothing

And this can happen, even despite the fact that you are following Apple’s guidelines and implementing Apple’s MVC pattern, so don’t feel bad. There is something wrong with the Apple’s MVC, but we’ll get back to it later.

Let’s define features of a good architecture:

  1. Balanced distribution of responsibilities among entities with strict roles.
  2. Testability usually comes from the first feature (and don’t worry: it is easy with appropriate architecture).
  3. Ease of use and a low maintenance cost.

Why Distribution?

Distribution keeps a fair load on our brain while we trying to figure out how things work. If you think the more you develop the better your brain will adapt to understanding complexity, then you are right. But this ability doesn’t scale linearly and reaches the cap very quickly. So the easiest way to defeat complexity is to divide responsibilities among multiple entities following the single responsibility principle.

Why Testability?

This is usually not a question for those who already felt gratitude to unit tests, which failed after adding new features or due to refactoring some intricacies of the class. This means the tests saved those developers from finding issues in runtime, which might happen when an app is on a user’s device and the fix takes a week to reach the user.

Why Ease of use?

This does not require an answer but it is worth mentioning that the best code is the code that has never been written. Therefore the less code you have, the less bugs you have. This means that desire to write less code should never be explained solely by laziness of a developer, and you should not favour a smarter solution closing your eyes to its maintenance cost.


MV(X) essentials

Nowadays we have many options when it comes to architecture design patterns:

First three of them assume putting the entities of the app into one of 3 categories:

  • Models — responsible for the domain data or a data access layer which manipulates the data, think of ‘Person’ or ‘PersonDataProvider’ classes.
  • Views — responsible for the presentation layer (GUI), for iOS environment think of everything starting with ‘UI’ prefix.
  • Controller/Presenter/ViewModel — the glue or the mediator between the Model and the View, in general responsible for altering the Model by reacting to the user’s actions performed on the View and updating the View with changes from the Model.

Having entities divided allows us to:

  • understand them better (as we already know)
  • reuse them (mostly applicable to the View and the Model)
  • test them independently

Let’s start with MV(X) patterns and get back to VIPER later.

MVC

How it used to be

Before discussing Apple’s vision of MVC let’s have a look on the traditional one.

Traditional MVC

In this case, the View is stateless. It is simply rendered by the Controller once the Model is changed. Think of the web page completely reloaded once you press on the link to navigate somewhere else. Although it is possible to implement the traditional MVC in iOS application, it doesn’t make much sense due to the architectural problem — all three entities are tightly coupled, each entity knows about the other two. This dramatically reduces reusability of each of them — that is not what you want to have in your application. For this reason, we skip even trying to write a canonical MVC example.

Traditional MVC doesn’t seems to be applicable to modern iOS development.

Apple’s MVC

Expectation

Cocoa MVC

The Controller is a mediator between the View and the Model so that they don’t know about each other. The least reusable is the Controller and this is usually fine for us, since we must have a place for all that tricky business logic that doesn’t fit into the Model.

In theory, it looks very straightforward, but you feel that something is wrong, right? You even heard people unabbreviating MVC as the Massive View Controller. Moreover, view controller offloading became an important topic for the iOS developers. Why does this happen if Apple just took the traditional MVC and improved it a bit?

Apple’s MVC

Reality

Realistic Cocoa MVC

Cocoa MVC encourages you to write Massive View Controllers, because they are so involved in View’s life cycle that it’s hard to say they are separate. Although you still have ability to offload some of the business logic and data transformation to the Model, you don’t have much choice when it comes to offloading work to the View, at most of times all the responsibility of the View is to send actions to the Controller. The view controller ends up being a delegate and a data source of everything, and is usually responsible for dispatching and cancelling the network requests and… you name it.

How many times have you seen code like this:

var userCell = tableView.dequeueReusableCellWithIdentifier(identifier) as UserCell
 userCell.configureWithUser(user)

The cell, which is the View configured directly with the Model, so MVC guidelines are violated, but this happens all the time, and usually people don’t feel it is wrong. If you strictly follow the MVC, then you supposed to configure the cell from the controller, and don’t pass the Model into the View, and this will increase the size of your Controller even more.

Cocoa MVC is reasonably unabbreviated as the Massive View Controller.

The problem might not be evident until it comes to the Unit Testing(hopefully, it does in your project). Since your view controller is tightly coupled with the view, it becomes difficult to test because you have to be very creative in mocking views and their life cycle, while writing the view controller’s code in such a way, that your business logic is separated as much as possible from the view layout code.

Let’s have a look on the simple playground example:

 import UIKit

 

struct Person { // Model
let firstName: String
let lastName: String
}
class GreetingViewController : UIViewController { // View + Controller
var person: Person!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: didTapButton:, forControlEvents: .TouchUpInside)
}
func didTapButton(button: UIButton) {
let greeting = Hello + + self.person.firstName + + self.person.lastName
self.greetingLabel.text = greeting
}
// layout code goes here
}
// Assembling of MVC
let model = Person(firstName: David, lastName: Blaine)
let view = GreetingViewController()
view.person = model;
MVC example

MVC assembling can be performed in the presenting view controller

This doesn’t seem very testable, right? We can move generation of greeting into the new GreetingModel class and test it separately, but we can’t test any presentation logic (although there is not much of such logic in the example above) inside the GreetingViewController without calling the UIView related methods directly (viewDidLoad, didTapButton) which might cause loading all views, and this is bad for the unit testing.

In fact, loading and testing UIViews on one simulator (e.g. iPhone 4S) doesn’t guarantee that it would work fine on the other devices (e.g. iPad), so I’d recommend to remove “Host Application” from your Unit Test target configuration and run your tests without your application running on simulator.

The interactions between the View and the Controller aren’t really testable with Unit Tests

With all that said, it might seems that Cocoa MVC is a pretty bad pattern to choose. But let’s assess it in terms of features defined in the beginning of the article:

  • Distribution the View and the Model in fact separated, but the View and the Controller are tightly coupled.
  • Testability — due to the bad distribution you’ll probably only test your Model.
  • Ease of use — the least amount of code among others patterns. In addition everyone is familiar with it, thus, it’s easily maintained even by the unexperienced developers.

Cocoa MVC is the pattern of your choice if you are not ready to invest more time in your architecture, and you feel that something with higher maintenance cost is an overkill for your tiny pet project.

Cocoa MVC is the best architectural pattern in terms of the speed of the development.

MVP

Cocoa MVC’s promises delivered

Passive View variant of MVP

Doesn’t it look exactly like the Apple’s MVC? Yes, it does, and it’s name is MVP (Passive View variant). But wait a minute… Does this mean that Apple’s MVC is in fact a MVP? No, its not, because if you recall, there, the View is tightly coupled with the Controller, while the MVP’s mediator, Presenter, has nothing to do with the life cycle of the view controller, and the View can be mocked easily, so there is no layout code in the Presenter at all, but it is responsible for updating the View with data and state.

What if I told you, the UIViewController is the View.

In terms of the MVP, the UIViewController subclasses are in fact the Views and not the Presenters. This distinction provides superb testability, which comes at cost of the development speed, because you have to make manual data and event binding, as you can see from the example:

 import UIKit

 

struct Person { // Model
let firstName: String
let lastName: String
}
protocol GreetingView: class {
func setGreeting(greeting: String)
}
protocol GreetingViewPresenter {
init(view: GreetingView, person: Person)
func showGreeting()
}
class GreetingPresenter : GreetingViewPresenter {
unowned let view: GreetingView
let person: Person
required init(view: GreetingView, person: Person) {
self.view = view
self.person = person
}
func showGreeting() {
let greeting = Hello + + self.person.firstName + + self.person.lastName
self.view.setGreeting(greeting)
}
}
class GreetingViewController : UIViewController, GreetingView {
var presenter: GreetingViewPresenter!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: didTapButton:, forControlEvents: .TouchUpInside)
}
func didTapButton(button: UIButton) {
self.presenter.showGreeting()
}
func setGreeting(greeting: String) {
self.greetingLabel.text = greeting
}
// layout code goes here
}
// Assembling of MVP
let model = Person(firstName: David, lastName: Blaine)
let view = GreetingViewController()
let presenter = GreetingPresenter(view: view, person: model)
view.presenter = presenter
MVP example

Important note regarding assembly

The MVP is the first pattern that reveals the assembly problem which happens due to having three actually separate layers. Since we don’t want the View to know about the Model, it is not right to perform assembly in presenting view controller (which is the View), thus we have to do it somewhere else. For example, we can make the app-wide Router service which will be responsible for performing assembly and the View-to-View presentation. This issue arises and has to be addressed not only in the MVP but also in all the following patterns.

Let’s look on the features of the MVP:

  • Distribution — we have the most of responsibilities divided between the Presenter and the Model, with the pretty dumb View (in the example above the Model is dumb as well).
  • Testability — is excellent, we can test most of the business logic due to the dumb View.
  • Easy of use — in our unrealistically simple example, the amount of code is doubled compared to the MVC, but at the same time, idea of the MVP is very clear.

MVP in iOS means superb testability and a lot of code.

MVP

With Bindings and Hooters

There is the other flavour of the MVP — the Supervising Controller MVP. This variant includes direct binding of the View and the Model while the Presenter (The Supervising Controller) still handles actions from the View and is capable of changing the View.

Supervising Presenter variant of the MVP

But as we have already learned before, vague responsibility separation is bad, as well as tight coupling of the View and the Model. That is similar to how things work in Cocoa desktop development.

Same as with the traditional MVC, I don’t see a point in writing an example for the flawed architecture.

MVVM

The latest and the greatest of the MV(X) kind

The MVVM is the newest of MV(X) kind thus, let’s hope it emerged taking into account problems MV(X) was facing previously.

In theory the Model-View-ViewModel looks very good. The View and the Model are already familiar to us, but also the Mediator, represented as the View Model.

MVVM

It is pretty similar to the MVP:

  • the MVVM treats the view controller as the View
  • There is no tight coupling between the View and the Model

In addition, it does binding like the Supervising version of the MVP; however, this time not between the View and the Model, but between the View and the View Model.

So what is the View Model in the iOS reality? It is basically UIKit independent representation of your View and its state. The View Model invokes changes in the Model and updates itself with the updated Model, and since we have a binding between the View and the View Model, the first is updated accordingly.

Bindings

I briefly mentioned them in the MVP part, but let’s discuss them a bit here. Bindings come out of box for the OS X development, but we don’t have them in the iOS toolbox. Of course we have the KVO and notifications, but they aren’t as convenient as bindings.

So, provided we don’t want to write them ourselves, we have two options:

In fact, nowadays, if you hear “MVVM” — you think ReactiveCocoa, and vice versa. Although it is possible to build the MVVM with the simple bindings, ReactiveCocoa (or siblings) will allow you to get most of the MVVM.

There is one bitter truth about reactive frameworks: the great power comes with the great responsibility. It’s really easy to mess up things when you go reactive. In other words, if do something wrong, you might spend a lot of time debugging the app, so just take a look at this call stack.

Reactive Debugging

In our simple example, the FRF framework or even the KVO is an overkill, instead we’ll explicitly ask the View Model to update using showGreeting method and use the simple property for greetingDidChange callback function.

 import UIKit

 

struct Person { // Model
let firstName: String
let lastName: String
}
protocol GreetingViewModelProtocol: class {
var greeting: String? { get }
var greetingDidChange: ((GreetingViewModelProtocol) -> ())? { get set } // function to call when greeting did change
init(person: Person)
func showGreeting()
}
class GreetingViewModel : GreetingViewModelProtocol {
let person: Person
var greeting: String? {
didSet {
self.greetingDidChange?(self)
}
}
var greetingDidChange: ((GreetingViewModelProtocol) -> ())?
required init(person: Person) {
self.person = person
}
func showGreeting() {
self.greeting = Hello + + self.person.firstName + + self.person.lastName
}
}
class GreetingViewController : UIViewController {
var viewModel: GreetingViewModelProtocol! {
didSet {
self.viewModel.greetingDidChange = { [unowned self] viewModel in
self.greetingLabel.text = viewModel.greeting
}
}
}
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self.viewModel, action: showGreeting, forControlEvents: .TouchUpInside)
}
// layout code goes here
}
// Assembling of MVVM
let model = Person(firstName: David, lastName: Blaine)
let viewModel = GreetingViewModel(person: model)
let view = GreetingViewController()
view.viewModel = viewModel
MVVM example

And again back to our feature assessment:

  • Distribution — it is not clear in our tiny example, but, in fact, the MVVM’s View has more responsibilities than the MVP’s View. Because the first one updates it’s state from the View Model by setting up bindings, when the second one just forwards all events to the Presenter and doesn’t update itself.
  • Testability — the View Model knows nothing about the View, this allows us to test it easily. The View might be also tested, but since it is UIKit dependant you might want to skip it.
  • Easy of use — its has the same amount of code as the MVP in our example, but in the real app where you’d have to forward all events from the View to the Presenter and to update the View manually, MVVM would be much skinnier if you used bindings.

The MVVM is very attractive, since it combines benefits of the aforementioned approaches, and, in addition, it doesn’t require extra code for the View updates due to the bindings on the View side. Nevertheless, testability is still on a good level.


VIPER

LEGO building experience transferred into the iOS app design

VIPER is our last candidate, which is particularly interesting because it doesn’t come from the MV(X) category.

By now, you must agree that the granularity in responsibilities is very good. VIPER makes another iteration on the idea of separating responsibilities, and this time we have five layers.

VIPER
  • Interactor — contains business logic related to the data (Entities) or networking, like creating new instances of entities or fetching them from the server. For those purposes you’ll use some Services and Managers which are not considered as a part of VIPER module but rather an external dependency.
  • Presenter — contains the UI related (but UIKit independent) business logic, invokes methods on the Interactor.
  • Entities — your plain data objects, not the data access layer, because that is a responsibility of the Interactor.
  • Router — responsible for the segues between the VIPER modules.

Basically, VIPER module can be a one screen or the whole user story of your application — think of authentication, which can be one screen or several related ones. How small are your “LEGO” blocks supposed to be? — It’s up to you.

If we compare it with the MV(X) kind, we’ll see a few differences of the distribution of responsibilities:

  • Model (data interaction) logic shifted into the Interactor with the Entities as dumb data structures.
  • Only the UI representation duties of the Controller/Presenter/ViewModel moved into the Presenter, but not the data altering capabilities.
  • VIPER is the first pattern which explicitly addresses navigation responsibility, which is supposed to be resolved by the Router.

Proper way of doing routing is a challenge for the iOS applications, the MV(X) patterns simply don’t address this issue.

The example doesn’t cover routing or interaction between modules, as those topics are not covered by the MV(X) patterns at all.

 import UIKit

 

struct Person { // Entity (usually more complex e.g. NSManagedObject)
let firstName: String
let lastName: String
}
struct GreetingData { // Transport data structure (not Entity)
let greeting: String
let subject: String
}
protocol GreetingProvider {
func provideGreetingData()
}
protocol GreetingOutput: class {
func receiveGreetingData(greetingData: GreetingData)
}
class GreetingInteractor : GreetingProvider {
weak var output: GreetingOutput!
func provideGreetingData() {
let person = Person(firstName: David, lastName: Blaine) // usually comes from data access layer
let subject = person.firstName + + person.lastName
let greeting = GreetingData(greeting: Hello, subject: subject)
self.output.receiveGreetingData(greeting)
}
}
protocol GreetingViewEventHandler {
func didTapShowGreetingButton()
}
protocol GreetingView: class {
func setGreeting(greeting: String)
}
class GreetingPresenter : GreetingOutput, GreetingViewEventHandler {
weak var view: GreetingView!
var greetingProvider: GreetingProvider!
func didTapShowGreetingButton() {
self.greetingProvider.provideGreetingData()
}
func receiveGreetingData(greetingData: GreetingData) {
let greeting = greetingData.greeting + + greetingData.subject
self.view.setGreeting(greeting)
}
}
class GreetingViewController : UIViewController, GreetingView {
var eventHandler: GreetingViewEventHandler!
let showGreetingButton = UIButton()
let greetingLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.showGreetingButton.addTarget(self, action: didTapButton:, forControlEvents: .TouchUpInside)
}
func didTapButton(button: UIButton) {
self.eventHandler.didTapShowGreetingButton()
}
func setGreeting(greeting: String) {
self.greetingLabel.text = greeting
}
// layout code goes here
}
// Assembling of VIPER module, without Router
let view = GreetingViewController()
let presenter = GreetingPresenter()
let interactor = GreetingInteractor()
view.eventHandler = presenter
presenter.view = view
presenter.greetingProvider = interactor
interactor.output = presenter

Yet again, back to the features:

  • Distribution — undoubtedly, VIPER is a champion in distribution of responsibilities.
  • Testability —no surprises here, better distribution — better testability.
  • Easy of use — finally, two above come in cost of maintainability as you already guessed. You have to write huge amount of interface for classes with very small responsibilities.

So what about LEGO?

While using VIPER, you might feel like building The Empire State Building from LEGO blocks, and that is a signal that you have a problem. Maybe, it’s too early to adopt VIPER for your application and you should consider something simpler. Some people ignore this and continue shooting out of cannon into sparrows. I assume they believe that their apps will benefit from VIPER at least in the future, even if now the maintenance cost is unreasonably high. If you believe the same, then I’d recommend you to try Generamba — a tool for generating VIPER skeletons. Although for me personally it feels like using an automated targeting system for cannon instead of simply taking a sling shot.

Conclusion

We went though several architectural patterns, and I hope you have found some answers to what bothered you, but I have no doubt that you realised that there is no silver bullet so choosing architecture pattern is a matter of weighting tradeoffs in your particular situation.

Therefore, it is natural to have a mix of architectures in same app. For example: you’ve started with MVC, then you realised that one particular screen became too hard to maintain efficiently with the MVC and switched to the MVVM, but only for this particular screen. There is no need to refactor other screens for which the MVC actually does work fine, because both of architectures are easily compatible.

iOS Architecture Patterns

Design Patterns in Swift

iOS Design Patterns – you’ve probably heard the term, but do you know what it means? While most developers probably agree that design patterns are very important, there aren’t many articles on the subject and we developers sometimes don’t pay too much attention to design patterns while writing code.

Design patterns are reusable solutions to common problems in software design. They’re templates designed to help you write code that’s easy to understand and reuse. They also help you create loosely coupled code so that you can change or replace components in your code without too much of a hassle.

If you’re new to design patterns, then I have good news for you! First, you’re already using tons of iOS design patterns thanks to the way Cocoa is built and the best practices you’re encouraged to use. Second, this tutorial will bring you up to speed on all the major (and not so major) iOS design patterns that are commonly used in Cocoa.

In this two-part tutorial, you will create a Music Library app that will display your albums and their relevant information.

In the process of developing this app, you’ll become acquainted with the most common Cocoa design patterns:

  • Creational: Singleton.
  • Structural: MVC, Decorator, Adapter, Facade.
  • Behavioral: Observer, and, Memento

Don’t be misled into thinking that this is an article about theory; you’ll get to use most of these design patterns in your app.

MVC – The King of Design Patterns

Model-View-Controller (MVC) is one of the building blocks of Cocoa and is undoubtedly the most-used design pattern of all. It classifies objects according to their general role in your application and encourages clean separation of code based on role.

The three roles are:

  • Model: The object that holds your application data and defines how to manipulate it. For example, in your application the Model is your Album class.
  • View: The objects that are in charge of the visual representation of the Model and the controls the user can interact with; basically, all the UIView-derived objects. In your application the View is represented by your AlbumView class.
  • Controller: The controller is the mediator that coordinates all the work. It accesses the data from the model and displays it with the views, listens to events and manipulates the data as necessary. Can you guess which class is your controller? That’s right: ViewController.

A good implementation of this design pattern in your application means that each object falls into one of these groups.

The communication between View to Model through Controller can be best described with the following diagram:

The Model notifies the Controller of any data changes, and in turn, the Controller updates the data in the Views. The View can then notify the Controller of actions the user performed and the Controller will either update the Model if necessary or retrieve any requested data.

You might be wondering why you can’t just ditch the Controller, and implement the View and Model in the same class, as that seems a lot easier.

It all comes down to code separation and reusability. Ideally, the View should be completely separated from the Model. If the View doesn’t rely on a specific implementation of the Model, then it can be reused with a different model to present some other data.

For example, if in the future you’d also like to add movies or books to your library, you could still use the same AlbumView to display your movie and book objects. Furthermore, if you want to create a new project that has something to do with albums, you could simply reuse your Album class, because it’s not dependent on any view. That’s the strength of MVC!

How to Use the MVC Pattern

First, you need to ensure that each class in your project is either a Controller, a Model or a View; don’t combine the functionality of two roles in one class. You’ve already done a good job so far by creating an Albumclass and an AlbumView class.

Second, in order to ensure that you conform to this method of work you should create three project groups to hold your code, one for each category.

Navigate to File\New\Group (or press on Command+Option+N) and name the group Model. Repeat the same process to create View and Controller groups.

Now drag Album.swift to the Model group. Drag AlbumView.swift to the View group, and finally drag ViewController.swift to the Controller group.

At this point the project structure should look like this:

Your project already looks a lot better without all those files floating around. Obviously you can have other groups and classes, but the core of the application is contained in these three categories.

Now that your components are organized, you need to get the album data from somewhere. You’ll create an API class to use throughout your code to manage the data — which presents an opportunity to discuss your next design pattern — the Singleton.

The Singleton Pattern

The Singleton design pattern ensures that only one instance exists for a given class and that there’s a global access point to that instance. It usually uses lazy loading to create the single instance when it’s needed the first time.

Note: Apple uses this approach a lot. For example: NSUserDefaults.standardUserDefaults(), UIApplication.sharedApplication(), UIScreen.mainScreen(), NSFileManager.defaultManager() all return a Singleton object.

You’re likely wondering why you care if there’s more than one instance of a class floating around. Code and memory is cheap, right?

There are some cases in which it makes sense to have exactly one instance of a class. For example, there’s only one instance of your application and one main screen for the device, so you only want one instance of each. Or, take a global configuration handler class: it’s easier to implement a thread-safe access to a single shared resource, such as a configuration file, than to have many class modifying the configuration file possibly at the same time.

How to Use the Singleton Pattern

Take a look at the diagram below:

The above image shows a Logger class with a single property (which is the single instance), and two methods: sharedInstance and init.

The first time a client asks for the sharedInstance, the instance property isn’t yet initialized, so you create a new instance of the class and return a reference to it.

The next time you call sharedInstance, instance is immediately returned without any initialization. This logic ensures that only one instance exists at one time.

You’ll implement this pattern by creating a singleton class to manage all the album data.

You’ll notice there’s a group called API in the project; this is where you’ll put all the classes that will provide services to your app. Create a new file inside this group by right-clicking the group and selecting New File. Select iOS > Cocoa Touch Class and then click Next. Set the class name to LibraryAPI, and the subclass to NSObject. Lastly choose Swift as the language. Click Next and then Create.

Now go to LibraryAPI.swift and insert this code inside the class definition.

//1
class var sharedInstance: LibraryAPI {
  //2
  struct Singleton {
    //3
    static let instance = LibraryAPI()
  }
  //4
  return Singleton.instance
}

There’s a lot going on in this short method:

  1. Create a class variable as a computed type property. The class variable, like class methods in Objective-C, is something you can call without having to instantiate the class LibraryAPI For more information about type properties please refer to Apple’s Swift documentation on
    properties
  2. Nested within the class variable is a struct called Singleton.
  3. Singleton wraps a static constant variable named instance. Declaring a property as static means this property only exists once. Also note that static properties in Swift are implicitly lazy, which means that Instance is not created until it’s needed. Also note that since this is a constant property, once this instance is created, it’s not going to create it a second time. This is the essence of the Singleton design pattern. The initializer is never called again once it has been instantiated.
  4. Returns the computed type property.

Note: To learn more about different ways to create a singleton in Swift refer to this: Github page

You now have a Singleton object as the entry point to manage the albums. Take it a step further and create a class to handle the persistence of your library data.

Now within the group API create a new file. Select iOS > Cocoa Touch class and then click Next. Set the class name to PersistencyManager, and make it a subclass of NSObject.

Open PersistencyManager.swift Add the following code inside the curly braces

private var albums = [Album]()

Here you declare a private property to hold album data. The array is mutable, so you can easily add and delete albums.

Now add the following initializer to the class:

override init() {
  //Dummy list of albums
  let album1 = Album(title: "Best of Bowie",
         artist: "David Bowie",
         genre: "Pop",
         coverUrl: "http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png",
         year: "1992")
  
  let album2 = Album(title: "It's My Life",
         artist: "No Doubt",
         genre: "Pop",
         coverUrl: "http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png",
         year: "2003")
  
  let album3 = Album(title: "Nothing Like The Sun",
         artist: "Sting",
         genre: "Pop",
         coverUrl: "http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png",
         year: "1999")
  
  let album4 = Album(title: "Staring at the Sun",
         artist: "U2",
         genre: "Pop",
         coverUrl: "http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png",
         year: "2000")
  
  let album5 = Album(title: "American Pie",
         artist: "Madonna",
         genre: "Pop",
         coverUrl: "http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png",
         year: "2000")
         
  albums = [album1, album2, album3, album4, album5]
}

In the initializer, you’re populating the array with five sample albums. If the above albums aren’t to your liking, feel free to replace them with the music you enjoy. :]

Now add the following functions to the class:

func getAlbums() -> [Album] {
  return albums
}

func addAlbum(album: Album, index: Int) {
  if (albums.count >= index) { 
    albums.insert(album, atIndex: index)
  } else {
    albums.append(album)
  }
}

func deleteAlbumAtIndex(index: Int) {
  albums.removeAtIndex(index)
}

These methods allow you to get, add, and delete albums.

Build your project just to make sure everything still compiles correctly.

At this point, you might wonder where the PersistencyManager class comes in since it’s not a Singleton. You’ll see the relationship between LibraryAPI and PersistencyManager in the next section where you’ll look at the Facade design pattern.

The Facade Design Pattern

The Facade design pattern provides a single interface to a complex subsystem. Instead of exposing the user to a set of classes and their APIs, you only expose one simple unified API.

The following image explains this concept:

 

The user of the API is completely unaware of the complexity that lies beneath. This pattern is ideal when working with a large number of classes, particularly when they are complicated to use or difficult to understand.

The Facade pattern decouples the code that uses the system from the interface and implementation of the classes you’re hiding; it also reduces dependencies of outside code on the inner workings of your subsystem. This is also useful if the classes under the facade are likely to change, as the facade class can retain the same API while things change behind the scenes.

For example, if the day comes when you want to replace your backend service, you won’t have to change the code that uses your API as it wont’ change.

How to Use the Facade Pattern

Currently you have PersistencyManager to save the album data locally and HTTPClient to handle the remote communication. The other classes in your project should not be aware of this logic, as they will be hiding behind the facade of LibraryAPI.

To implement this pattern, only LibraryAPI should hold instances of PersistencyManager and HTTPClient. Then, LibraryAPI will expose a simple API to access those services.

The design looks like the following:

 

LibraryAPI will be exposed to other code, but will hide the HTTPClient and PersistencyManager complexity from the rest of the app.

Open LibraryAPI.swift and add the following constant properties to the class:

private let persistencyManager: PersistencyManager
private let httpClient: HTTPClient
private let isOnline: Bool

isOnline determines if the server should be updated with any changes made to the albums list, such as added or deleted albums.

You now need to initialize these variables via init. Add the initializer to the class next:

override init() {
  persistencyManager = PersistencyManager()
  httpClient = HTTPClient()
  isOnline = false
  
  super.init()
}

The HTTP client doesn’t actually work with a real server and is only here to demonstrate the usage of the facade pattern, so isOnline will always be false.

Next, add the following three methods to LibraryAPI.swift:

func getAlbums() -> [Album] {
  return persistencyManager.getAlbums()
}

func addAlbum(album: Album, index: Int) {
  persistencyManager.addAlbum(album, index: index)
  if isOnline {
    httpClient.postRequest("/api/addAlbum", body: album.description)
  }
}

func deleteAlbum(index: Int) {
  persistencyManager.deleteAlbumAtIndex(index)
  if isOnline {
    httpClient.postRequest("/api/deleteAlbum", body: "\(index)")
  }
}

Take a look at addAlbum(_:index:). The class first updates the data locally, and then if there’s an internet connection, it updates the remote server. This is the real strength of the Facade; when some class outside of your system adds a new album, it doesn’t know — and doesn’t need to know — of the complexity that lies underneath.

Note: When designing a Facade for classes in your subsystem, remember that nothing prevents the client from accessing these “hidden” classes directly. Don’t be stingy with defensive code and don’t assume that all the clients will necessarily use your classes the same way the Facade uses them.

Build and run your app. You’ll see two empty views, and a toolbar. The top view will be used to display your album covers, and the bottom view will be used to display a table of information related to that album.

You’ll need something to display the album data on screen — which is a perfect use for your next design pattern: the Decorator.

The Decorator Design Pattern

The Decorator pattern dynamically adds behaviors and responsibilities to an object without modifying its code. It’s an alternative to subclassing where you modify a class’s behavior by wrapping it with another object.

In Swift there are two very common implementations of this pattern: Extensions and Delegation.

Extensions

Adding extensions is an extremely powerful mechanism that allows you to add new functionality to existing classes, structures or enumeration types without having to subclass. What’s also really awesome is you can extend code you don’t have access to, and enhance their functionality. That means you can add your own methods to Cocoa classes such as UIView and UIImage!

For example, new methods that are added at compile time can be executed like normal methods of the extended class. It’s slightly different from the classic definition of a decorator, because a extension doesn’t hold an instance of the class it extends.

How to Use Extensions

Imagine a situation in which you have an Album object that you want to present inside a table view:
Where will the album titles come from? Album is a Model object, so it doesn’t care how you present the data. You’ll need some external code to add this functionality to the Album class, but without modifying the class directly.

You’ll create a extension that will extend the Album class; it will define a new method that returns a data structure which can be used easily with UITableView.

The data structure will look like the following:

To add a Extensions to Album, navigate to File\New\File… and select the iOS > Source > Swift File template, and then click Next. Enter AlbumExtensions and click Create.

Go to AlbumExtensions.swift and add the following extension:

extension Album {
  func ae_tableRepresentation() -> (titles:[String], values:[String]) {
    return (["Artist", "Album", "Genre", "Year"], [artist, title, genre, year])
  }
}

Notice there’s a ae_ at the beginning of the method name, as an abbreviation of the name of the extension: AlbumExtension. Conventions like this will help prevent collisions with methods (including possible private methods you might not know about) in the original implementation.

Note: Classes can of course override a superclass’s method, but with extensions you can’t. Methods or properties in an extension cannot have the same name as methods or properties in the original class.

Consider for a moment how powerful this pattern can be:

  • You’re using properties directly from Album.
  • You have added to the Album class but you haven’t subclassed it. If you need to sub-class Album, you can still do that too.
  • This simple addition lets you return a UITableViewish representation of an Album, without modifying Album‘s code.

Delegation

The other Decorator design pattern, Delegation, is a mechanism in which one object acts on behalf of, or in coordination with, another object. For example, when you use a UITableView, one of the methods you must implement is tableView(_:numberOfRowsInSection:).

You can’t expect the UITableView to know how many rows you want to have in each section, as this is application-specific. Therefore, the task of calculating the amount of rows in each section is passed on to the UITableView delegate. This allows the UITableView class to be independent of the data it displays.

The UITableView object does its job of displaying a table view. However, eventually it will need some information that it doesn’t have. Then, it turns to its delegates and sends a message asking for additional information. In Objective-C’s implementation of the delegate pattern, a class can declare optional and required methods through a protocol. You’ll cover protocols a bit later in this tutorial.

It might seem easier to just subclass an object and override the necessary methods, but consider that you can only subclass based on a single class. If you want an object to be the delegate of two or more other objects, you won’t be able to achieve this by subclassing.

Note: This is an important pattern. Apple uses this approach in most of the UIKit classes: UITableView, UITextView, UITextField, UIWebView, UIAlert, UIActionSheet, UICollectionView, UIPickerView, UIGestureRecognizer, UIScrollView. The list goes on and on.

How to Use the Delegate Pattern

Open up ViewController.swift and add these private properties to the class:

private var allAlbums = [Album]()
private var currentAlbumData : (titles:[String], values:[String])?
private var currentAlbumIndex = 0

Next, replace viewDidLoad with this code:

override func viewDidLoad() {
  super.viewDidLoad()
  //1
  self.navigationController?.navigationBar.translucent = false
  currentAlbumIndex = 0

  //2
  allAlbums = LibraryAPI.sharedInstance.getAlbums()

  // 3
  // the uitableview that presents the album data
  dataTable.delegate = self
  dataTable.dataSource = self
  dataTable.backgroundView = nil
  view.addSubview(dataTable!)		
}

Here’s a breakdown of the above code:

  1. Turn off translucency on the navigation bar.
  2. Get a list of all the albums via the API. Remember, the plan is to use the facade of LibraryAPI rather than PersistencyManager directly!
  3. This is where you setup the UITableView. You declare that the view controller is the UITableView delegate/data source; therefore, all the information required by UITableView will be provided by the view controller. Note that you can actually set the delegate and datasource in a storyboard, if your table view is created there.

Now, add the following method to ViewController.swift:

func showDataForAlbum(albumIndex: Int) {
  // defensive code: make sure the requested index is lower than the amount of albums
  if (albumIndex < allAlbums.count && albumIndex > -1) {
    //fetch the album
    let album = allAlbums[albumIndex]
    // save the albums data to present it later in the tableview
    currentAlbumData = album.ae_tableRepresentation()
  } else {
    currentAlbumData = nil
  }
  // we have the data we need, let's refresh our tableview
  dataTable!.reloadData()
}

showDataForAlbum() fetches the required album data from the array of albums. When you want to present the new data, you just need to call reloadData. This causes UITableView to ask its delegate such things as how many sections should appear in the table view, how many rows in each section, and how each cell should look.

Add the following line to the end of viewDidLoad

self.showDataForAlbum(currentAlbumIndex)

This loads the current album at app launch. And since currentAlbumIndex was previously set to 0, this shows the first album in the collection.

Now it’s time to implement the data source protocol! You can add the list of protocols implemented by the class right on the class declaration line. Or, to keep things tidy you can add them as extensions, which you’re already familiar with.

Add the following extensions to the bottom of the file. Make sure you add these lines after the closing brace of the class definition!

extension ViewController: UITableViewDataSource {
}

extension ViewController: UITableViewDelegate {
}

This is how you make your delegate conform to a protocol — think of it as a promise made by the delegate to fulfill the method’s contract. Here, you indicate that ViewController will conform to the UITableViewDataSource and UITableViewDelegate protocols. This way UITableView can be absolutely certain that the required methods are implemented by its delegate.

Add the following code to the UITableViewDataSource extension:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  if let albumData = currentAlbumData {
    return albumData.titles.count
  } else {
    return 0
  }
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  var cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
  if let albumData = currentAlbumData {
    cell.textLabel!.text = albumData.titles[indexPath.row]
    cell.detailTextLabel!.text = albumData.values[indexPath.row]
  }
  return cell
}

tableView(_:numberOfRowsInSection:) returns the number of rows to display in the table view, which matches the number of titles in the data structure.

tableView(_:cellForRowAtIndexPath:) creates and returns a cell with the title and its value.

Note: You can actually add the methods to the main class declaration or to the extension; the compiler doesn’t care that the data source methods are actually inside the UITableViewDataSource extension. For humans reading the code though, this kind of organization really helps with readability.

The Adapter Pattern

An Adapter allows classes with incompatible interfaces to work together. It wraps itself around an object and exposes a standard interface to interact with that object.

If you’re familiar with the Adapter pattern then you’ll notice that Apple implements it in a slightly different manner – Apple uses protocols to do the job. You may be familiar with protocols like UITableViewDelegate, UIScrollViewDelegate, NSCoding and NSCopying. As an example, with the NSCopying protocol, any class can provide a standard copy method.

How to Use the Adapter Pattern

The horizontal scroller mentioned before will look like this:

To begin implementing it, right click on the View group in the Project Navigator, select New File… and select, iOS > Cocoa Touch class and then click Next. Set the class name to HorizontalScroller and make it a subclass of UIView.

Open HorizontalScroller.swift and insert the following code above the class HorizontalScroller line:

@objc protocol HorizontalScrollerDelegate {
}

This defines a protocol named HorizontalScrollerDelegate. You’re including @objc before the protocol declaration so you can make use of @optional delegate methods like in Objective-C.

You define the required and optional methods that the delegate will implement between the protocols curly braces. So add the following protocol methods:

// ask the delegate how many views he wants to present inside the horizontal scroller
func numberOfViewsForHorizontalScroller(scroller: HorizontalScroller) -> Int
// ask the delegate to return the view that should appear at <index>
func horizontalScrollerViewAtIndex(scroller: HorizontalScroller, index:Int) -> UIView
// inform the delegate what the view at <index> has been clicked
func horizontalScrollerClickedViewAtIndex(scroller: HorizontalScroller, index:Int)
// ask the delegate for the index of the initial view to display. this method is optional
// and defaults to 0 if it's not implemented by the delegate
optional func initialViewIndex(scroller: HorizontalScroller) -> Int

Here you have both required and optional methods. Required methods must be implemented by the delegate and usually contain some data that is absolutely required by the class. In this case, the required details are the number of views, the view at a specific index, and the behavior when the view is tapped. The optional method here is the initial view; if it’s not implemented then the HorizontalScroller will default to the first index.

In HorizontalScroller.swift, add the following code to the HorizontalScroller class definition:

weak var delegate: HorizontalScrollerDelegate?

The attribute of the property you created above is defined as weak. This is necessary in order to prevent a retain cycle. If a class keeps a strong reference to its delegate and the delegate keeps a strong reference back to the conforming class, your app will leak memory since neither class will release the memory allocated to the other. All properties in swift are strong by default!

The delegate is an optional, so it’s possible whoever is using this class doesn’t provide a delegate. But if they do, it will conform to HorizontalScrollerDelegate and you can be sure the protocol methods will be implemented there.

Add a few more properties to the class:

// 1
private let VIEW_PADDING = 10
private let VIEW_DIMENSIONS = 100
private let VIEWS_OFFSET = 100

// 2
private var scroller : UIScrollView!
// 3
var viewArray = [UIView]()

Taking each comment block in turn:

  1. Define constants to make it easy to modify the layout at design time. The view’s dimensions inside the scroller will be 100 x 100 with a 10 point margin from its enclosing rectangle.
  2. Create the scroll view containing the views.
  3. Create an array that holds all the album covers.

Next you need to implement the initializers. Add the following methods:

override init(frame: CGRect) {
  super.init(frame: frame)
  initializeScrollView()
}

required init(coder aDecoder: NSCoder) {
  super.init(coder: aDecoder)
  initializeScrollView()
}

func initializeScrollView() {
  //1
  scroller = UIScrollView()
  addSubview(scroller)
  
  //2
  scroller.setTranslatesAutoresizingMaskIntoConstraints(false)
  //3
  self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1.0, constant: 0.0))
  self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing, multiplier: 1.0, constant: 0.0))
  self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0.0))
  self.addConstraint(NSLayoutConstraint(item: scroller, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0.0))

  //4
  let tapRecognizer = UITapGestureRecognizer(target: self, action:Selector("scrollerTapped:"))
  scroller.addGestureRecognizer(tapRecognizer)
}

The initializers delegate most of the work to initializeScrollView(). Here’s what’s going on in that method:

  1. Create’s a new UIScrollView instance and add it to the parent view.
  2. Turn off autoresizing masks. This is so you can apply your own constraints
  3. Apply constraints to the scrollview. You want the scroll view to completely fill the HorizontalScroller
  4. Create a tap gesture recognizer. The tap gesture recognizer detects touches on the scroll view and checks if an album cover has been tapped. If so, it will notify the HorizontalScroller delegate.

Now add this method:

func scrollerTapped(gesture: UITapGestureRecognizer) {
    let location = gesture.locationInView(gesture.view)
    if let delegate = delegate {
      for index in 0..<delegate.numberOfViewsForHorizontalScroller(self) {
        let view = scroller.subviews[index] as! UIView
        if CGRectContainsPoint(view.frame, location) {
          delegate.horizontalScrollerClickedViewAtIndex(self, index: index)
          scroller.setContentOffset(CGPoint(x: view.frame.origin.x - self.frame.size.width/2 + view.frame.size.width/2, y: 0), animated:true)
          break
        }
      }
    }
  }

The gesture passed in as a parameter lets you extract the location with locationInView().

Next, you invoke numberOfViewsForHorizontalScroller() on the delegate. The HorizontalScroller instance has no information about the delegate other than knowing it can safely send this message since the delegate must conform to the HorizontalScrollerDelegate protocol.

For each view in the scroll view, perform a hit test using CGRectContainsPoint to find the view that was tapped. When the view is found, call the delegate method horizontalScrollerClickedViewAtIndex. Before you break out of the for loop, center the tapped view in the scroll view.

Next add the following to access an album cover from the scroller:

func viewAtIndex(index :Int) -> UIView {
  return viewArray[index]
}

viewAtIndex simply returns the view at a particular index. You will be using this method later to highlight the album cover you have tapped on.

Now add the following code to reload the scroller:

func reload() {
    // 1 - Check if there is a delegate, if not there is nothing to load.
    if let delegate = delegate {
      //2 - Will keep adding new album views on reload, need to reset.
      viewArray = []
      let views: NSArray = scroller.subviews

			// 3 - remove all subviews
			for view in views {
				view.removeFromSuperview()
			}

      // 4 - xValue is the starting point of the views inside the scroller
      var xValue = VIEWS_OFFSET
      for index in 0..<delegate.numberOfViewsForHorizontalScroller(self) {
        // 5 - add a view at the right position
        xValue += VIEW_PADDING
        let view = delegate.horizontalScrollerViewAtIndex(self, index: index)
        view.frame = CGRectMake(CGFloat(xValue), CGFloat(VIEW_PADDING), CGFloat(VIEW_DIMENSIONS), CGFloat(VIEW_DIMENSIONS))
        scroller.addSubview(view)
        xValue += VIEW_DIMENSIONS + VIEW_PADDING
        // 6 - Store the view so we can reference it later
        viewArray.append(view)
      }
      // 7
      scroller.contentSize = CGSizeMake(CGFloat(xValue + VIEWS_OFFSET), frame.size.height)

      // 8 - If an initial view is defined, center the scroller on it
      if let initialView = delegate.initialViewIndex?(self) {
        scroller.setContentOffset(CGPoint(x: CGFloat(initialView)*CGFloat((VIEW_DIMENSIONS + (2 * VIEW_PADDING))), y: 0), animated: true)
      }
    }
  }

The reload method is modeled after reloadData in UITableView; it reloads all the data used to construct the horizontal scroller.

Stepping through the code comment-by-comment:

  1. Checks to see if there is a delegate before we perform any reload.
  2. Since you’re clearing the album covers, you also need to reset the viewArray. If not you will have a ton of views left over from the previous covers.
  3. Remove all the subviews previously added to the scroll view.
  4. All the views are positioned starting from the given offset. Currently it’s 100, but it can be easily tweaked by changing the constant VIEW_OFFSET at the top of the file.
  5. The HorizontalScroller asks its delegate for the views one at a time and it lays them next to each another horizontally with the previously defined padding.
  6. Store the view in viewArray to keep track of all the views in the scroll view.
  7. Once all the views are in place, set the content offset for the scroll view to allow the user to scroll through all the albums covers.
  8. The HorizontalScroller checks if its delegate implements initialViewIndex(). This check is necessary because that particular protocol method is optional. If the delegate doesn’t implement this method, 0 is used as the default value. Finally, this piece of code sets the scroll view to center the initial view defined by the delegate.

You execute reload when your data has changed. You also need to call this method when you add HorizontalScroller to another view. Add the following code to HorizontalScroller.swift to cover the latter scenario:

override func didMoveToSuperview() {
  reload()
}

didMoveToSuperview is called on a view when it’s added to another view as a subview. This is the right time to reload the contents of the scroller.

The last piece of the HorizontalScroller puzzle is to make sure the album you’re viewing is always centered inside the scroll view. To do this, you’ll need to perform some calculations when the user drags the scroll view with their finger.

Add the following method:

 func centerCurrentView() {
    var xFinal = Int(scroller.contentOffset.x) + (VIEWS_OFFSET/2) + VIEW_PADDING
    let viewIndex = xFinal / (VIEW_DIMENSIONS + (2*VIEW_PADDING))
    xFinal = viewIndex * (VIEW_DIMENSIONS + (2*VIEW_PADDING))
		scroller.setContentOffset(CGPoint(x: xFinal, y: 0), animated: true)
    if let delegate = delegate {
      delegate.horizontalScrollerClickedViewAtIndex(self, index: Int(viewIndex))
    }  
 }

The above code takes into account the current offset of the scroll view and the dimensions and the padding of the views in order to calculate the distance of the current view from the center. The last line is important: once the view is centered, you then inform the delegate that the selected view has changed.

To detect that the user finished dragging inside the scroll view, you’ll need to implement some UIScrollViewDelegate methods. Add the following class extension to the bottom of the file; remember, this must be added after the curly braces of the main class declaration!

extension HorizontalScroller: UIScrollViewDelegate {
  func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
      centerCurrentView()
    }
  }
  
  func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    centerCurrentView()
  }
}

scrollViewDidEndDragging(_:willDecelerate:) informs the delegate when the user finishes dragging. The decelerate parameter is true if the scroll view hasn’t come to a complete stop yet. When the scroll action ends, the the system calls scrollViewDidEndDecelerating. In both cases you should call the new method to center the current view since the current view probably has changed after the user dragged the scroll view.

Lastly don’t forget to set the delegate. Within initializeScrollView() add the following code after scroller = UIScrollView():

scroller.delegate = self;

Your HorizontalScroller is ready for use! Browse through the code you’ve just written; you’ll see there’s not one single mention of the Album or AlbumView classes. That’s excellent, because this means that the new scroller is truly independent and reusable.

Build your project to make sure everything compiles properly.

Now that HorizontalScroller is complete, it’s time to use it in your app. First, open Main.storyboard. Click on the top gray rectangular view and click on the identity inspector. Change the class name to HorizontalScroller.

Next, open the assistant editor and control drag from the gray rectangular view to ViewController.swift to create an outlet. Name the name the outlet scroller,

Next, open ViewController.swift. It’s time to start implementing some of the HorizontalScrollerDelegate methods!

Add the following extension to the bottom of the file:

extension ViewController: HorizontalScrollerDelegate {
  func horizontalScrollerClickedViewAtIndex(scroller: HorizontalScroller, index: Int) {
    //1
    let previousAlbumView = scroller.viewAtIndex(currentAlbumIndex) as! AlbumView
    previousAlbumView.highlightAlbum(didHighlightView: false)
    //2
    currentAlbumIndex = index
    //3
    let albumView = scroller.viewAtIndex(index) as! AlbumView
    albumView.highlightAlbum(didHighlightView: true)
    //4
    showDataForAlbum(index)
  }
}

Let’s go over the delegate method you just implemented line by line:

  1. First you grab the previously selected album, and deselect the album cover.
  2. Store the current album cover index you just clicked
  3. Grab the album cover that is currently selected and highlight the selection.
  4. Display the data for the new album within the table view.

Next, add the following method to the extension:

func numberOfViewsForHorizontalScroller(scroller: HorizontalScroller) -> (Int) {
  return allAlbums.count
}

This, as you’ll recognize, is the protocol method returning the number of views for the scroll view. Since the scroll view will display covers for all the album data, the count is the number of album records.

Now, add this code:

func horizontalScrollerViewAtIndex(scroller: HorizontalScroller, index: Int) -> (UIView) {
    let album = allAlbums[index]
    let albumView = AlbumView(frame: CGRect(x: 0, y: 0, width: 100, height: 100), albumCover: album.coverUrl)
    if currentAlbumIndex == index {
      albumView.highlightAlbum(didHighlightView: true)
    } else {
      albumView.highlightAlbum(didHighlightView: false)
    }
    return albumView
  }

Here you create a new AlbumView, next check to see whether or not the user has selected this album. Then you can set it as highlighted or not depending on whether the album is selected. Lastly, you pass it to the HorizontalScroller.

That’s it! Only three short methods to display a nice looking horizontal scroller.

Yes, you still need to actually create the scroller and add it to your main view but before doing that, add the following method to the main class definition:

  func reloadScroller() {
    allAlbums = LibraryAPI.sharedInstance.getAlbums()
    if currentAlbumIndex < 0 {
      currentAlbumIndex = 0
    } else if currentAlbumIndex >= allAlbums.count {
      currentAlbumIndex = allAlbums.count - 1
    }
    scroller.reload()
    showDataForAlbum(currentAlbumIndex)
  }

This method loads album data via LibraryAPI and then sets the currently displayed view based on the current value of the current view index. If the current view index is less than 0, meaning that no view was currently selected, then the first album in the list is displayed. Otherwise, the last album is displayed.

Now, initialize the scroller by adding the following code to the end of viewDidLoad:

scroller.delegate = self
reloadScroller()

Since the HorizontalScroller was created in the storyboard, all you need to do is set the delegate, and call reloadScroller(), which will load the subviews for the scroller to display album data.

Note: If a protocol becomes too big and is packed with a lot of methods, you should consider breaking it into several smaller protocols. UITableViewDelegate and UITableViewDataSource are a good example, since they are both protocols of UITableView. Try to design your protocols so that each one handles one specific area of functionality.

Build and run your project and take a look at your awesome new horizontal scroller:

Uh, wait. The horizontal scroller is in place, but where are the covers?

Ah, that’s right — you didn’t implement the code to download the covers yet. To do that, you’ll need to add a way to download images. Since all your access to services goes through LibraryAPI, that’s where this new method would have to go. However, there are a few things to consider first:

  1. AlbumView shouldn’t work directly with LibraryAPI. You don’t want to mix view logic with communication logic.
  2. For the same reason, LibraryAPI shouldn’t know about AlbumView.
  3. LibraryAPI needs to inform AlbumView once the covers are downloaded since the AlbumView has to display the covers.

Sounds like a conundrum? Don’t despair, you’ll learn how to do this using the Observer pattern! :]

The Observer Pattern

In the Observer pattern, one object notifies other objects of any state changes. The objects involved don’t need to know about one another – thus encouraging a decoupled design. This pattern’s most often used to notify interested objects when a property has changed.

The usual implementation requires that an observer registers interest in the state of another object. When the state changes, all the observing objects are notified of the change.

If you want to stick to the MVC concept (hint: you do), you need to allow Model objects to communicate with View objects, but without direct references between them. And that’s where the Observer pattern comes in.

Cocoa implements the observer pattern in two familiar ways: Notifications and Key-Value Observing (KVO).

Notifications

Not be be confused with Push or Local notifications, Notifications are based on a subscribe-and-publish model that allows an object (the publisher) to send messages to other objects (subscribers/listeners). The publisher never needs to know anything about the subscribers.

Notifications are heavily used by Apple. For example, when the keyboard is shown/hidden the system sends a UIKeyboardWillShowNotification/UIKeyboardWillHideNotification, respectively. When your app goes to the background, the system sends a UIApplicationDidEnterBackgroundNotification notification.

Note: Open up UIApplication.swift, at the end of the file you’ll see a list of over 20 notifications sent by the system.

How to Use Notifications

Go to AlbumView.swift and insert the following code to the end of the init(frame: CGRect, albumCover: String) initializer:

NSNotificationCenter.defaultCenter().postNotificationName("BLDownloadImageNotification", object: self, userInfo: ["imageView":coverImage, "coverUrl" : albumCover])

This line sends a notification through the NSNotificationCenter singleton. The notification info contains the UIImageView to populate and the URL of the cover image to be downloaded. That’s all the information you need to perform the cover download task.

Add the following line to init in LibraryAPI.swift, directly after super.init():

NSNotificationCenter.defaultCenter().addObserver(self, selector:"downloadImage:", name: "BLDownloadImageNotification", object: nil)

This is the other side of the equation: the observer. Every time an AlbumView class posts a BLDownloadImageNotification notification, since LibraryAPI has registered as an observer for the same notification, the system notifies LibraryAPI. Then LibraryAPI calls downloadImage() in response.

However, before you implement downloadImage() you must remember to unsubscribe from this notification when your class is deallocated. If you do not properly unsubscribe from a notification your class registered for, a notification might be sent to a deallocated instance. This can result in application crashes.

Add the following method to LibraryAPI.swift:

deinit {
  NSNotificationCenter.defaultCenter().removeObserver(self)
}

When this object is deallocated, it removes itself as an observer from all notifications it had registered for.

There’s one more thing to do. It would probably be a good idea to save the downloaded covers locally so the app won’t need to download the same covers over and over again.

Open PersistencyManager.swift and add the methods below:

func saveImage(image: UIImage, filename: String) {
  let path = NSHomeDirectory().stringByAppendingString("/Documents/\(filename)")
  let data = UIImagePNGRepresentation(image)
  data.writeToFile(path, atomically: true)
}

func getImage(filename: String) -> UIImage? {
  var error: NSError?
  let path = NSHomeDirectory().stringByAppendingString("/Documents/\(filename)")
  let data = NSData(contentsOfFile: path, options: .UncachedRead, error: &error)
  if let unwrappedError = error {
    return nil
  } else {
    return UIImage(data: data!)
  }
}

This code is pretty straightforward. The downloaded images will be saved in the Documents directory, and getImage() will return nil if a matching file is not found in the Documents directory.

Now add the following method to LibraryAPI.swift:

  func downloadImage(notification: NSNotification) {
    //1
    let userInfo = notification.userInfo as! [String: AnyObject]
    var imageView = userInfo["imageView"] as! UIImageView?
    let coverUrl = userInfo["coverUrl"] as! String

    //2
    if let imageViewUnWrapped = imageView {
      imageViewUnWrapped.image = persistencyManager.getImage(coverUrl.lastPathComponent)
      if imageViewUnWrapped.image == nil {
        //3
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
          let downloadedImage = self.httpClient.downloadImage(coverUrl as String)
          //4
          dispatch_sync(dispatch_get_main_queue(), { () -> Void in
            imageViewUnWrapped.image = downloadedImage
            self.persistencyManager.saveImage(downloadedImage, filename: coverUrl.lastPathComponent)
          })
        })
      }
    }
  }

Here’s a breakdown of the above code:

  1. downloadImage is executed via notifications and so the method receives the notification object as a parameter. The UIImageView and image URL are retrieved from the notification.
  2. Retrieve the image from the PersistencyManager if it’s been downloaded previously.
  3. If the image hasn’t already been downloaded, then retrieve it using HTTPClient.
  4. When the download is complete, display the image in the image view and use the PersistencyManagerto save it locally.

Again, you’re using the Facade pattern to hide the complexity of downloading an image from the other classes. The notification sender doesn’t care if the image came from the web or from the file system.

Build and run your app and check out the beautiful covers inside your HorizontalScroller.

Stop your app and run it again. Notice that there’s no delay in loading the covers because they’ve been saved locally. You can even disconnect from the Internet and your app will work flawlessly. However, there’s one odd bit here: the spinner never stops spinning! What’s going on?

You started the spinner when downloading the image, but you haven’t implemented the logic to stop the spinner once the image is downloaded. You could send out a notification every time an image has been downloaded, but instead, you’ll do that using the other Observer pattern, KVO.

Key-Value Observing (KVO)

In KVO, an object can ask to be notified of any changes to a specific property; either its own or that of another object. If you’re interested, you can read more about this on Apple’s KVO Programming Guide.

How to Use the KVO Pattern

As mentioned above, the KVO mechanism allows an object to observe changes to a property. In your case, you can use KVO to observe changes to the image property of the UIImageView that holds the image.

Open AlbumView.swift and add the following code to init(frame:albumCover:), just after you add coverImage as a subView:

coverImage.addObserver(self, forKeyPath: "image", options: nil, context: nil)

This adds self, which is the current class, as an observer for the image property of coverImage.

You also need to unregister as an observer when you’re done. Still in AlbumView.swift, add the following code:

deinit {
  coverImage.removeObserver(self, forKeyPath: "image")
}

Finally, add this method:

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
  if keyPath == "image" {
    indicator.stopAnimating()
  }
}

You must implement this method in every class acting as an observer. The system executes this method every time an observed property changes. In the above code, you stop the spinner when the “image” property changes. This way, when an image is loaded, the spinner will stop spinning.

Build and run your project. The spinner should disappear.

Note: Always remember to remove your observers when they’re deallocated, or else your app will crash when the subject tries to send messages to these non-existent observers!

If you play around with your app a bit and terminate it, you’ll notice that the state of your app isn’t saved. The last album you viewed won’t be the default album when the app launches.

To correct this, you can make use of the next pattern on the list: Memento.

The Memento Pattern

The memento pattern captures and externalizes an object’s internal state. In other words, it saves your stuff somewhere. Later on, this externalized state can be restored without violating encapsulation; that is, private data remains private.

How to Use the Memento Pattern

Add the following two methods to ViewController.swift:

//MARK: Memento Pattern
func saveCurrentState() {
  // When the user leaves the app and then comes back again, he wants it to be in the exact same state
  // he left it. In order to do this we need to save the currently displayed album.
  // Since it's only one piece of information we can use NSUserDefaults.
  NSUserDefaults.standardUserDefaults().setInteger(currentAlbumIndex, forKey: "currentAlbumIndex")
}
	
func loadPreviousState() {
  currentAlbumIndex = NSUserDefaults.standardUserDefaults().integerForKey("currentAlbumIndex")
  showDataForAlbum(currentAlbumIndex)
}

saveCurrentState saves the current album index to NSUserDefaultsNSUserDefaults is a standard data store provided by iOS for saving application specific settings and data.

loadPreviousState loads the previously saved index. This isn’t quite the full implementation of the Memento pattern, but you’re getting there.

Now, Add the following line to viewDidLoad in ViewController.swift before the scroller.delegate = self:

loadPreviousState()

That loads the previously saved state when the app starts. But where do you save the current state of the app for loading from? You’ll use Notifications to do this. iOS sends a UIApplicationDidEnterBackgroundNotification notification when the app enters the background. You can use this notification to call saveCurrentState. Isn’t that convenient?

Add the following line to the end of viewDidLoad:

NSNotificationCenter.defaultCenter().addObserver(self, selector:"saveCurrentState", name: UIApplicationDidEnterBackgroundNotification, object: nil)

Now, when the app is about to enter the background, the ViewController will automatically save the current state by calling saveCurrentState.

As always, you’ll need to un-register for notifications. Add the following code to the class:

deinit {
  NSNotificationCenter.defaultCenter().removeObserver(self)
}

This ensures you remove the class as an observer when the ViewController is deallocated.

Build and run your app. Navigate to one of the albums, send the app to the background with the Home button (Command+Shift+H if you are on the simulator) and then shut down your app from Xcode. Relaunch, and check that the previously selected album is centered:

It looks like the album data is correct, but the scroller isn’t centered on the correct album. What gives?

This is what the optional method initialViewIndexForHorizontalScroller was meant for! Since that method’s not implemented in the delegate, ViewController in this case, the initial view is always set to the first view.

To fix that, add the following code to ViewController.swift:

func initialViewIndex(scroller: HorizontalScroller) -> Int {
  return currentAlbumIndex
}

Now the HorizontalScroller first view is set to whatever album is indicated by currentAlbumIndex. This is a great way to make sure the app experience remains personal and resumable.

Run your app again. Scroll to an album as before, put the app in the background, stop the app, then relaunch to make sure the problem is fixed:

If you look at PersistencyManager‘s init, you’ll notice the album data is hardcoded and recreated every time PersistencyManager is created. But it’s better to create the list of albums once and store them in a file. How would you save the Album data to a file?

One option is to iterate through Album‘s properties, save them to a plist file and then recreate the Album instances when they’re needed. This isn’t the best option, as it requires you to write specific code depending on what data/properties are there in each class. For example, if you later created a Movie class with different properties, the saving and loading of that data would require new code.

Additionally, you won’t be able to save the private variables for each class instance since they are not accessible to an external class. That’s exactly why Apple created the archiving mechanism.

Archiving

One of Apple’s specialized implementations of the Memento pattern is Archiving. This converts an object into a stream that can be saved and later restored without exposing private properties to external classes. You can read more about this functionality in Chapter 16 of the iOS 6 by Tutorials book. Or in Apple’s Archives and Serializations Programming Guide.

How to Use Archiving

First, you need to declare that Album can be archived by conforming to the NSCoding protocol. Open Album.swift and change the class line as follows:

class Album: NSObject, NSCoding {

Add the following two methods to Album.swift:

required init(coder decoder: NSCoder) {
  super.init()
  self.title = decoder.decodeObjectForKey("title") as! String
  self.artist = decoder.decodeObjectForKey("artist") as! String
  self.genre = decoder.decodeObjectForKey("genre") as! String
  self.coverUrl = decoder.decodeObjectForKey("cover_url") as! String
  self.year = decoder.decodeObjectForKey("year") as! String
}

	
func encodeWithCoder(aCoder: NSCoder) {
  aCoder.encodeObject(title, forKey: "title")
  aCoder.encodeObject(artist, forKey: "artist")
  aCoder.encodeObject(genre, forKey: "genre")
  aCoder.encodeObject(coverUrl, forKey: "cover_url")
  aCoder.encodeObject(year, forKey: "year")
}

As part of the NSCoding protocol, encodeWithCoder will be called when you ask for an Album instance to be archived. Conversely, the init(coder:) initializer will be used to reconstruct or unarchive from a saved instance. It’s simple, yet powerful.

Now that the Album class can be archived, add the code that actually saves and loads the list of albums.

Add the following method to PersistencyManager.swift:

func saveAlbums() {
  var filename = NSHomeDirectory().stringByAppendingString("/Documents/albums.bin")
  let data = NSKeyedArchiver.archivedDataWithRootObject(albums)
  data.writeToFile(filename, atomically: true)
}

This will be the method that’s called to save the albums. NSKeyedArchiver archives the album array into a file called albums.bin.

When you archive an object which contains other objects, the archiver automatically tries to recursively archive the child objects and any child objects of the children and so on. In this instance, the archival starts with albums, which is an array of Album instances. Since Array and Album both support the NSCopying interface, everything in the array is automatically archived.

Now replace init in PersistencyManager.swift with the following code:

override init() {
  super.init()
  if let data = NSData(contentsOfFile: NSHomeDirectory().stringByAppendingString("/Documents/albums.bin")) {
    let unarchiveAlbums = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [Album]?
      if let unwrappedAlbum = unarchiveAlbums {
        albums = unwrappedAlbum
      }
  } else {
    createPlaceholderAlbum()
  }
}
	
func createPlaceholderAlbum() {
  //Dummy list of albums
  let album1 = Album(title: "Best of Bowie",
		     artist: "David Bowie",
		     genre: "Pop",
		     coverUrl: "http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png",
		     year: "1992")
		
let album2 = Album(title: "It's My Life",
		   artist: "No Doubt",
		   genre: "Pop",
		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png",
		   year: "2003")
		
let album3 = Album(title: "Nothing Like The Sun",
	           artist: "Sting",
		   genre: "Pop",
		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png",
		   year: "1999")
		
let album4 = Album(title: "Staring at the Sun",
		   artist: "U2",
		   genre: "Pop",
		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png",
		   year: "2000")
		
let album5 = Album(title: "American Pie",
		   artist: "Madonna",
		   genre: "Pop",
		   coverUrl: "http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png",
		   year: "2000")
  albums = [album1, album2, album3, album4, album5]
  saveAlbums()
}

You have moved the placeholder album creation code into a separate method createPlaceholderAlbum()for readability. In the new code, NSKeyedUnarchiver loads the album data from the file, if it exists. If it doesn’t exist, it creates the album data and immediately saves it for the next launch of the app.

You’ll also want to save the album data every time the app goes into the background. This might not seem necessary now but what if you later add the option to change album data? Then you’d want this to ensure that all your changes are saved.

Since the main application accesses all services via LibraryAPI, this is how the application will let PersistencyManager know that it needs to save album data.

Now add the method implementation to LibraryAPI.swift:

func saveAlbums() {
  persistencyManager.saveAlbums()
}

This code simply passes on a call to LibraryAPI to save the albums on to PersistencyMangaer.

Add the following code to the end of saveCurrentState in ViewController.swift:

LibraryAPI.sharedInstance.saveAlbums()

And the above code uses LibraryAPI to trigger the saving of album data whenever the ViewController saves its state.

Build your app to check that everything compiles.

Unfortunately, there’s no easy way to check if the data persistency is correct though. You can check the simulator Documents folder for your app in Finder to see that the album data file is created but in order to see any other changes you’d have to add in the ability to change album data.

But instead of changing data, what if you added an option to delete albums you no longer want in your library? Additionally, wouldn’t it be nice to have an undo option if you delete an album by mistake?

Final Touches (Alternative of command Pattern in Objective-C)

You are going to add the final touches to your music application by allowing the user to perform delete actions to remove an album, or undo actions in case they change their mind!

Add the following property to ViewController:

// We will use this array as a stack to push and pop operation for the undo option
var undoStack: [(Album, Int)] = []

This creates an empty undo stack. The undoStack will hold a tuple of two arguments. The first is an Albumand the second is the index of the album.

Add the following code after reloadScroller() in viewDidLoad::

let undoButton = UIBarButtonItem(barButtonSystemItem: .Undo, target: self, action:"undoAction")
undoButton.enabled = false;
let space = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target:nil, action:nil)
let trashButton = UIBarButtonItem(barButtonSystemItem: .Trash, target:self, action:"deleteAlbum")
let toolbarButtonItems = [undoButton, space, trashButton]
toolbar.setItems(toolbarButtonItems, animated: true)

The above code creates a toolbar with two buttons and a flexible space between them. The undo button is disabled here because the undo stack starts off empty. Note that the toolbar is already in the storyboard, so all you need to do is set the toolbar items.

You’ll add three method to ViewController.swift for handling album management actions: add, delete, and undo.

The first is the method for adding a new album:

func addAlbumAtIndex(album: Album,index: Int) {
  LibraryAPI.sharedInstance.addAlbum(album, index: index)
  currentAlbumIndex = index
  reloadScroller()
}

Here you add the album, set it as the current album index, and reload the scroller.

Next comes the delete method:

func deleteAlbum() {
  //1
  var deletedAlbum : Album = allAlbums[currentAlbumIndex]
  //2
  var undoAction = (deletedAlbum, currentAlbumIndex)
  undoStack.insert(undoAction, atIndex: 0)
  //3
  LibraryAPI.sharedInstance.deleteAlbum(currentAlbumIndex)
  reloadScroller()
  //4
  let barButtonItems = toolbar.items as! [UIBarButtonItem]
  var undoButton : UIBarButtonItem = barButtonItems[0]
  undoButton.enabled = true
  //5
  if (allAlbums.count == 0) {
    var trashButton : UIBarButtonItem = barButtonItems[2]
    trashButton.enabled = false
  }
}

Consider each commented section below:

  1. Get the album to delete.
  2. Create a variable called undoAction which stores a tuple of Album and the index of the album. You then add the tuple into the stack
  3. Use LibraryAPI to delete the album from the data structure and reload the scroller.
  4. Since there’s an action in the undo stack, you need to enable the undo button.
  5. Lastly check to see if there are any albums left; if there aren’t any you can disable the trash button.

Finally, add the method for the undo action:

func undoAction() {
  let barButtonItems = toolbar.items as! [UIBarButtonItem]
  //1		
  if undoStack.count > 0 {
    let (deletedAlbum, index) = undoStack.removeAtIndex(0)
    addAlbumAtIndex(deletedAlbum, index: index)
  }
  //2		
  if undoStack.count == 0 {
    var undoButton : UIBarButtonItem = barButtonItems[0]
    undoButton.enabled = false
  }
  //3		
  let trashButton : UIBarButtonItem = barButtonItems[2]
  trashButton.enabled = true
}

Finally consider the comments for the method above:

  1. The method “pops” the object out of the stack, giving you a tuple containing the deleted Album and its index. You then proceed to add the album back.
  2. Since you also deleted the last object in the stack when you “popped” it, you now need to check if the stack is empty. If it is, that means that there are no more actions to undo. So you disable the Undo button.
  3. You also know that since you undid an action, there should be at least one album cover. Hence you enable the trash button.

Build and run your app to test out your undo mechanism, delete an album (or two) and hit the Undo button to see it in action

This is also a good place to test out whether changes to your album data is retained between sessions. Now, if you delete an album, send the app to the background, and then terminate the app, the next time you start the app the displayed album list should reflect the deletion.

If you want to get all the albums back, just delete the app and run it again from Xcode to install a fresh copy with the starter data.

Design Patterns in Swift

XCode Instruments with Swift

This Instruments tutorial will show you how to use the most important features of the tool called Instruments that ships with Xcode. It allows you to check your code for performance issues, memory issues, reference cycles, and other problems.

In this tutorial you’re going to learn:

  • How to determine hot-spots in your code using the Time Profiler instrument in order to make your code more efficient, and
  • How to detect and fix memory management issues such as strong reference cycles in your code using the Allocations instrument and the Visual Memory Debugger.

All set? Get ready to dive into the fascinating world of Instruments! :]

Getting Started

For this Instruments tutorial you won’t go through the process of creating an application from scratch; instead, a sample project has been provided for you. Your task is to go through the application and improve it using Instruments as your guide — very similar to how you would go about optimizing your own apps!

Download the starter project then unzip it and open it up in Xcode.

This sample app uses the Flickr API to search for images. To use the API you’ll need an API key. For demo projects, you can generate a sample key on Flickr’s website. Just perform any search at: http://www.flickr.com/services/api/explore/?method=flickr.photos.search and copy the API key out of the URL at the bottom – it follows the “&api_key=” all the way to the next “&”.

For example, if the URL is:
http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=6593783 efea8e7f6dfc6b70bc03d2afb&format=rest&api_sig=f24f4e98063a9b8ecc8b522b238d5e2f
Then the API key is: 6593783efea8e7f6dfc6b70bc03d2afb.

Paste it into the top of the FlickrAPI.swift file, replacing the existing API key.

Note that this sample API key is changed every day or so, so you’ll occasionally have to regenerate a new key. The app will alert you whenever the key is no longer valid.

Build and run the app, perform a search, click the result, and you’ll see something like the following:

 

Browse through the application and check out the basic functions. You might be tempted to think that once the UI looks great the app is ready for store submission. However, you’re about to see the value that using Instruments can add to your app.

The remainder of this tutorial will show you how to find and fix the issues that still exist in the app. You’ll see how Instruments can make debugging problems a whole lot easier! :]

Time for Profiling

The first instrument you’ll look at is the Time Profiler. At measured intervals, Instruments will halt the execution of the program and take a stack trace on each running thread. Think of it as clicking the pause button in Xcode’s debugger.

Here’s a sneak preview of the Time Profiler:

This screen displays the Call Tree. The Call Tree shows the amount of time spent executing in various methods within an app. Each row is a different method that the program’s execution path has followed. The time spent in each method can be determined from the number of times the profiler is stopped in each method.

For instance, if 100 samples are done at 1 millisecond intervals, and a particular method is found to be at the top of the stack in 10 samples, then you can deduce that approximately 10% of the total execution time — 10 milliseconds — was spent in that method. It’s a fairly crude approximation, but it works!

Note: In general, you should always profile your app on an actual device, instead of the simulator. The iOS simulator has all of the horsepower of your Mac behind it, whereas a device will have all of the limitations of mobile hardware. Your app may seem to run just fine in the simulator, but you might discover a performance issue once it’s running on a real device.

So without any further ado, time to get instrumenting!

From Xcode’s menu bar, select Product\Profile, or press ⌘I. This will build the app and launch Instruments. You will be greeted with a selection window that looks like this:

These are all different templates that come with Instruments.

Select the Time Profiler instrument and click Choose. This will open up a new Instruments document. Click the red record button in the top left to start recording and launch the app. You may be asked for your password to authorize Instruments to analyze other processes — fear not, it’s safe to provide here! :]

In the Instruments window, you can see the time counting up, and a little arrow moving from left to right above the graph in the center of the screen. This indicates that the app is running.

Now, start using the app. Search for some images, and drill down into one or more of the search results. You have probably noticed that going into a search result is tediously slow, and scrolling through a list of search results is also incredibly annoying – it’s a terribly clunky app!

Well, you’re in luck, for you’re about to embark on fixing it! However, you’re first going to get a quick run down on what you’re looking at in Instruments.

First, make sure the view selector on the right hand side of the toolbar has both options selected, like so:

That will ensure that all panels are open. Now study the screenshot below and the explanation of each section beneath it:

  1. These are the recording controls. The red ‘record’ button will stop & start the app currently being profiled when it is clicked (it toggles between a record and stop icon). The pause button does exactly what you’d expect and pauses the current execution of the app.
  2. This is the run timer. The timer counts how long the app being profiled has been running, and how many times it has been run. Click the stop button and then restart the app, you’ll see the display now show Run 2 of 2.
  3. This is called a track. In the case of the Time Profiler template you selected, there’s just one instrument so there’s just one track. You’ll learn more about the specifics of the graph shown here later in the tutorial.
  4. This is the detail panel. It shows the main information about the particular instrument you’re using. In this case, it’s showing the methods which are “hottest” — that is, the ones that have used up the most CPU time.Click on the bar at the top of this area on the word Profile and select Samples. Here you can view every single sample. Click on a few samples, and you’ll see the captured stack trace appear in the Extended Detail inspector to the right. Switch back to Profile when you’re done.
  5. This is the inspectors panel. There are two inspectors: Extended Detail and Run Info. You’ll be learning more about these options shortly.

Drilling Deep

Perform an image search, and drill into the results. I personally like searching for “dog”, but choose whatever you wish – you might be one of those cat people! :]

Now, scroll up and down the list a few times so that you’ve got a good amount of data in the Time Profiler. You should notice the numbers in the middle of the screen changing and the graph filling in; this tells you that CPU cycles are being used.

No table view is ready to ship until it scrolls like butter!

To help pinpoint the problem, you’ll set some options. Click the Stop button and, below the detail panel, click the Call Tree button. In the popover that appears, select Separate by Thread, Invert Call Tree and Hide System Libraries. It will look like this:

Here’s what each option is doing to the data displayed in the table to the left:

  • Separate by State: This option groups results by your application’s life cycle state and is a useful way to inspect how much work your app is doing and when.
  • Separate by Thread: Each thread should be considered separately. This enables you to understand which threads are responsible for the greatest amount of CPU use.
  • Invert Call Tree: With this option, the stack trace is considered from most recent to least recent.
  • Hide System Libraries: When this option is selected, only symbols from your own app are displayed. It’s often useful to select this option, since usually you only care about where the CPU is spending time in your own code – you can’t do much about how much CPU the system libraries are using!
  • Flatten Recursion: This option treats recursive functions (ones which call themselves) as one entry in each stack trace, rather than multiple.
  • Top Functions: Enabling this makes Instruments consider the total time spent in a function as the sum of the time directly within that function, as well as the time spent in functions called by that function. So if function A calls B, then A’s time is reported as the time spent in A PLUS the time spent in B. This can be really useful, as it lets you pick the largest time figure each time you descend into the call stack, zeroing in on your most time-consuming methods.

Scan the results to identify which rows have the highest percentage in the Weight column. Notice that the row with the Main Thread is using up a significant proportion of CPU cycles. Unfold this row by clicking the small arrow to the left of the text, and drill down until you see of one of your own methods (marked with the “person” symbol). Although some values may be slightly different, the order of the entries should be similar to the table below:

Well, that certainly doesn’t look too good. The vast majority of time is spent in the method that applies the ‘tonal’ filter to the thumbnail photos. That shouldn’t come as too much of a shock to you, as the table loading and scrolling were the clunkiest parts of the UI, and that’s when the table cells are constantly being updated.

To find out more about what’s going on within that method, double-click its row in the table. Doing so will bring up the following view:

Well that’s interesting, isn’t it! applyTonalFilter() is a method added to UIImage in an extension, and, a lot of time is spent invoking the method that creates the CGImage output after applying the image filter.

There’s not really much that can be done to speed this up: creating the image is quite an intensive process, and takes as long as it takes. Let’s try stepping back and seeing where applyTonalFilter() is called from. Click Root in the breadcrumb trail at the top of the code view to get back to the previous screen:

Now click the small arrow to the left of the applyTonalFilter row at the top of the table. This will show the caller of applyTonalFilter. You may need to unfold the next row too; when profiling Swift, there will sometimes be duplicate rows in the Call Tree, prefixed with @objc. You’re interested in the first row that’s prefixed with the “person” symbol, which indicates it belongs to your app’s target:

In this case, this row refers to the results collection view’s (_:cellForItemAt:). Double-click the row to see the associated code from the project.

Now you can see what the problem is. Take a look at line 74; the method to apply the tonal filter takes a long time to execute, and it’s called directly from collectionView(_:cellForItemAt:), which will block the main thread (and therefore the entire UI) each time it asks for a filtered image.

Offloading the Work

To solve this, you’ll take two steps: first, offload the image filtering onto a background thread with DispatchQueue.global().async; then cache each image after it’s been generated. There is a small, simple image caching class (with the catchy name ImageCache) included in the starter project, that simply stores images in memory and retrieves them with a given key.

You could now switch to Xcode and manually find the source file you’re looking at in Instruments, but there’s a handy Open in Xcode button right in front of your eyes. Locate it in the panel just above the code and click it:

There you go! Xcode opens up at exactly the right place. Boom!

Now, within collectionView(_:cellForItemAt:), replace the call to loadThumbnail(for:completion:) with the following:

ImageCache.shared.loadThumbnail(for: flickrPhoto) { result in

  switch result {
          
    case .success(let image):
          
      if cell.flickrPhoto == flickrPhoto {
        if flickrPhoto.isFavourite {
          cell.imageView.image = image
        } else {
          if let cachedImage = ImageCache.shared.image(forKey: "\(flickrPhoto.id)-filtered") {
            cell.imageView.image = cachedImage
           }
           else {
             DispatchQueue.global().async {
               if let filteredImage = image.applyTonalFilter() {
                 ImageCache.shared.set(filteredImage, forKey: "\(flickrPhoto.id)-filtered")
                    
                   DispatchQueue.main.async {
                     cell.imageView.image = filteredImage
         	          }
                }
             }
          }
        }
     }
          
  case .failure(let error):
    print("Error: \(error)")
  }
}

The first section of this code is the same as it was before, and is concerned with loading the Flickr photo’s thumbnail image from the web. If the photo is favorited, the cell displays the thumbnail as-is. However, if the photo isn’t favorited, the tonal filter is applied.

This is where you changed things: first, you check to see if a filtered image for this photo exists in the image cache. If yes, great; you display that image in the image view. If not, you dispatch the call to apply the tonal filter onto a background queue. This will allow the UI to remain responsive whilst the images are filtered. When the filter has been applied, you save the image in the cache, and update the image view on the main queue.

That’s the filtered images taken care of, but there’s still the original Flickr thumbnails to be taken care of. Open up Cache.swift and find loadThumbnail(for:completion:). Replace it with the following:

func loadThumbnail(for photo: FlickrPhoto, completion: @escaping FlickrAPI.FetchImageCompletion) {
  if let image = ImageCache.shared.image(forKey: photo.id) {
    completion(Result.success(image))
  }
  else {
    FlickrAPI.loadImage(for: photo, withSize: "m") { result in
      if case .success(let image) = result {
        ImageCache.shared.set(image, forKey: photo.id)
      }
     completion(result)
    }
  }
}

This is quite similar to the way you handled filtered images. If an image already exists in the cache then you call the completion closure straight away with the cached image. Otherwise, you load the image from Flickr and store it in the cache.

Re-run the app in Instruments by navigating to Product\Profile (or ⌘I – remember, those shortcuts will really save you some time).

Notice that this time Xcode doesn’t ask you for which instrument to use. This is because you still have a window open for this app, and Instruments assumes you want to run again with the same options.

Perform a few more searches, and notice that this time the UI is not quite so clunky! The image filter is now applied asynchronously and the images are cached in the background, so once they only have to be filtered once. You’ll see a number of dispatch_worker_threads in the Call Tree – these are handling the heavy lifting of applying image filters.

Looks great! Is it time to ship it? Not yet! :]

Allocations, Allocations, Allocations

So what bug are you going to track down next? :]

There’s something hidden in the project that you probably don’t know is there. You’ve likely heard about memory leaks. But what you may not know is that there are actually two kinds of leaks:

  1. True memory leaks are where an object is no longer referenced by anything but still allocated – that means the memory can never be re-used.
    Even with Swift and ARC helping manage memory, the most common kind of memory leak is a retain cycle or strong reference cycle. This is when two objects hold strong references to one another, so that each object keeps the other one from being deallocated. This means that their memory is never released.
  2. Unbounded memory growth is where memory continues to be allocated and is never given a chance to be deallocated. If this continues forever, then at some point the system’s memory will be filled and you’ll have a big memory problem on your hands. On iOS this means that the app will be killed by the system.

The next instrument covered in this tutorial is the Allocations instrument. This gives you detailed information about all the objects that are being created and the memory that backs them; it also shows you retain counts of each object.

To start afresh with a new instruments profile, quit the Instruments app, don’t worry about saving this particular run. Now press ⌘I, select the Allocations instrument from the list and click Choose.

You should now be presented with the Allocations instrument. It should look familiar to you because it looks a lot like the time profiler.

Click the Record button on the top left to run the app. This time you’ll notice two tracks. For the purposes of this tutorial, you will only be concerned with the one called All Heap and Anonymous VM.

With the Allocations instrument running on the app, make five different searches in the app but do not drill down into the results yet. Make sure the searches have some results. Now let the app settle a bit by waiting a few seconds.

You should have noticed that the graph in the All Heap and Anonymous VM track has been rising. This is telling you that memory is being allocated. It’s this feature that will guide you to finding unbounded memory growth.

What you’re going to perform is a “generation analysis”. To do this, click the button called Mark Generation. You’ll find the button at the bottom of the detail panel:

Click it and you will see a red flag appear in the track, like so:

The purpose of generation analysis is to perform an action multiple times, and see if memory is growing in an unbounded fashion. Drill into a search, wait a few seconds for the images to load, and then go back to the main page. Then mark the generation again. Do this repeatedly for different searches.

After a drilling into a few searches, Instruments will look like this:

At this point, you should be getting suspicious. Notice how the blue graph is going up with each search that you drill into. Well, that certainly isn’t good. But wait, what about memory warnings? You know about those, right? Memory warnings are iOS’s way of telling an app that things are getting tight in the memory department, and you need to clear out some memory.

It’s possible that this growth is not just due to your app; it could be something in the depths of UIKit that’s holding onto memory. Give the system frameworks and your app a chance to clear their memory first before pointing a finger at either one.

Simulate a memory warning by selecting Instrument\Simulate Memory Warning in Instruments’ menu bar, or Hardware\Simulate Memory Warning from the simulator’s menu bar. You’ll notice that memory usage dips a little, or perhaps not at all. Certainly not back to where it should be. So there’s still unbounded memory growth happening somewhere.

Instruments: Talkin’ Bout My Generation

The reason for marking a generation after each iteration of drilling into a search is that you can see what memory has been allocated between each generation. Take a look in the detail panel and you’ll see a bunch of generations.

Within each generation, you’ll see all the objects that were allocated and still resident at the time that generation was marked. Subsequent generations will contain just the objects since the previous generation was marked.

Look at the Growth column and you’ll see that there is definitely growth occurring somewhere. Open up one of the generations and you’ll see this:

Wow, that’s a lot of objects! Where do you start?

Easy. Click the Growth header to sort by size, make sure the heaviest objects are at the top. Right near the top of each generation, you’ll notice a row labeled ImageIO_jpeg_Data, which certainly sounds like something dealt with in your app. Click on the arrow on the left of ImageIO_jpeg_Data to display the memory addresses associated with this item. Select the first memory address to display the associated stack trace in the Extended Detail inspector on the panel to the right:

This stack trace shows you the point when this specific object was created. The parts of the stack trace in gray are in system libraries; the parts in black are in your app’s code. Hmm, something looks familiar: Some of the black entries show your old friend collectionView(_:cellForItemAt:). Double click any of those entries, Instruments will bring up the code in its context.

Take a look through the method, you’ll see it calling set(_:forKey:) on line 81. Remember, this method caches an image in case it is used again later on in the app. Ah! Well that certainly sounds like it could be a problem! :]

Again, click the Open in Xcode button to jump back into Xcode. Open Cache.swift and take a look at the implementation of set(_:forKey:).:

func set(_ image: UIImage, forKey key: String) {
  images[key] = image
}

This adds an image to a dictionary which is keyed on the photo ID of the Flickr photo. But if you look through the code, you’ll notice that the image is never cleared from that dictionary!

That’s where your unbounded memory growth is coming from: everything is working as it should, but the app never removes things from the cache — it only ever adds them!

To fix the problem, all you need to do is have ImageCache listen to the memory warning notification that UIApplication fires. When ImageCache receives this, it must be a good citizen and clear its cache.

To make ImageCache listen to the notification, open up Cache.swift and add the following initializer and de-initializer to the class:

init() {
   NotificationCenter.default.addObserver(forName: Notification.Name.UIApplicationDidReceiveMemoryWarning, object: nil, queue: .main) { [weak self] notification in
    self?.images.removeAll(keepingCapacity: false)
  }
}
  
deinit {
  NotificationCenter.default.removeObserver(self)
}

This registers an observer for UIApplicationDidReceiveMemoryWarningNotification to execute the closure above which clears images.

All that the code needs to do is remove all objects in the cache. This will ensure that nothing is holding onto the images any more and they will be deallocated.

To test this fix, fire up Instruments again (from Xcode with ⌘I) and repeat the steps you followed previously. Don’t forget to simulate a memory warning at the end.

Note: Make sure you launch from Xcode, triggering a build, rather than just hitting the red button in Instruments, in order to make sure you’re using the latest code. You may also want to Build and Run first before Profiling, as sometimes Xcode doesn’t seem to update the build of the app in the simulator to the latest version if you just Profile.

This time the generation analysis should look like this:

You’ll notice the memory usage dropped after the memory warning. There’s still some memory growth overall, but nowhere near as much as before.

The reason there’s still some growth is really due to the system libraries, and there’s not much you can do about those. It appears that the system libraries are not freeing all of their memory, which may be by design or may be a bug. All you can do in your app is free up as much memory as possible, and you’ve already done that! :]

Well done! One more issue patched up! It must be time to ship by now! Oh, wait – there’s still the issue of the first type of leak that you haven’t yet addressed.

Strong Reference Cycles

As mentioned earlier, a strong reference cycle occurs when two objects hold strong references to each other, therefore memory can’t ever be deallocated. You can detect these cycles using the Allocations instrument in a different way.

Close Instruments and head back to Xcode. Choose Product\Profile once again, and select the Allocations template.

This time around, you won’t be using generation analysis. Instead, you’ll look at the number of objects of different types that are hanging around in memory. Click the Record button to start this run. You should already see a huge number of objects filling up the detail panel – too much to look through! To help narrow down only the objects of interest, type “Instruments” as a filter in the field in the bottom-left corner.

The two columns worth noting in Instruments are # Persistent and # Transient. The Persistent column keeps a count of the number of objects of each type that currently exist in memory. The Transient column shows the number of objects that have existed but have since been deallocated. Persistent objects are using up memory, transient objects have had their memory released.

You should see that there is a persistent instance of ViewController – that makes sense, because that’s the screen you’re currently looking at. There’s also an instance of the app’s AppDelegate.

Back to the app! Perform a search and drill into the results. Notice that a bunch of extra objects are now showing up in Instruments: the SearchResultsViewController and the ImageCache amongst others. The ViewController instance is still persistent, because it’s needed by its navigation controller. That’s fine.

Now tap the back button in the app. The SearchResultsViewController has now been popped off the navigation stack, so it should be deallocated. But it’s still showing a # Persistent count of 1 in the Allocations summary! Why is it still there?

Try performing another two searches and tap the back button after each one. There are now 3SearchResultsViewControllers?! The fact that these view controllers are hanging around in memory means that something is keeping a strong reference to them. Looks like you have a strong reference cycle!

Your main clue in this situation is that not only is the SearchResultsViewController persisting, but so are all the SearchResultsCollectionViewCells. It’s likely that the reference cycle is between these two classes.

Thankfully, the Visual Memory Debugger, introduced in Xcode 8, is a neat tool that can help you further diagnose memory leaks and retain cycles. The Visual Memory Debugger is not part of Xcode’s Instrument’s suite but is nevertheless such a useful tool that it’s worth including in this tutorial. Cross-referencing insights from both the Allocations instrument and the Visual Memory Debugger is a powerful technique that can make your debugging workflow a lot more effective.

Getting Visual

Quit the Allocations instrument and exit the Instruments suite.

Before starting the Visual Memory Debugger, enable Malloc Stack logging in the Xcode scheme editor like this: Click on the Instruments Tutorial scheme at the top of the window (next to the stop button) and select Edit Scheme. In the pop-up that appears, click the Run section and switch to the Diagnostics tab. Check the box that says Malloc Stack and select the Live Allocations Only option and click close.

Start the app directly from Xcode. Like before, perform at least 3 searches to accumulate some data.

Now activate the Visual Memory Debugger like this:

  1. Switch to the Debug navigator.
  2. Click this icon and choose View Memory Graph Hierarchy from the pop up.
  3. Click on the entry for the SearchResultsCollectionViewCell.
  4. You can click any object on the graph to view details on the inspectors pane.
  5. You can view details in this area. Switch to the Memory inspector here.

The Visual Memory Debugger pauses your app and displays a visual representation of objects in memory and the references between them.

As highlighted in the screenshot above, the Visual Memory Debugger displays the following information:

  • Heap contents (Debug navigator pane): This shows you the list of all types and instances allocated in memory at the moment your app was paused. Clicking on a type unfolds the row to show you the separate instances of the type in memory.
  • Memory graph (main window): The main window shows a visual representation of objects in memory. The arrows between objects represent the references between them (strong and weak relationships).
  • Memory Inspector (Utilities pane): This includes details such as the class name and hierarchy, and whether a reference is strong or weak.

Notice how some rows in the Debug navigator have a bracketed number next to them. The number in brackets indicates how many instances of that specific type are in memory. In the screenshot above, you can see that after a handful of searches, the Visual Memory Debugger confirms the results you saw in the Allocations instrument, i.e. anywhere from 20 to (if you scrolled to the end of the search results) 60 SearchResultsCollectionViewCell instances for every SearchResultsViewController instance are being retained in memory.

Use the arrow on the left side of the row to unfold the type and show each SearchResultsViewControllerinstance in memory. Clicking an individual instance will display that instance and any references to it in the main window.

Notice the arrows pointing to the SearchResultsViewController instance. It looks like there are a few Swift closure contexts instances with references to the same view controller instance. Looks a little suspect, doesn’t it? Let’s take a closer look. Select one of the arrows to display more information in the Utilities pane about the reference between one of these closure instances and the SearchResultsViewController.

In the Memory Inspector, you can see that the reference between the Swift closure context and the SearchResultsViewController is strong. If you select the reference between the SearchResultsCollectionViewCell and the Swift closure context, you will see that this is marked strong as well. You can also see that the closure’s name is “heartToggleHandler.” A-ha! This is declared in the SearchResultsCollectionViewCell class!

Select the instance of SearchResultsCollectionViewCell in the main window to show more information on the inspector pane.

In the backtrace, you can see that the cell instance was initialized in collectionView(_:cellForItemAt:). When you hover over this row in the backtrace, a small arrow will appear. Clicking the arrow will take you to this method in Xcode’s code editor. Neato!

In collectionView(_:cellForItemAt:), locate where each cell’s heartToggleHandler variable is set. You’ll see the following lines of code:

cell.heartToggleHandler = { isStarred in
  self.collectionView.reloadItems(at: [indexPath])
}

This closure handles when the heart button in a collection view cell is tapped. This is where the strong reference cycle lies, but it’s kind of hard to spot unless you’ve come across one before. But thanks to the Visual Memory Debugger, you were able to follow where the trail all the way to this piece of code!

The closure cell refers to the SearchResultsViewController using self, which creates a strong reference. The closure captures self. Swift actually forces you to explicitly use the word self in closures (whereas you can usually drop it when referring to methods and properties of the current object). This helps you be more aware of the fact you’re capturing it. The SearchResultsViewController also has a strong reference to the cells, via their collection view.

To break a strong reference cycle, you define a capture list as part of the closure’s definition. A capture list can be used to declare instances that are captured by closures as being either weak or unowned:

  • Weak should be used when the captured reference might become nil in the future. If the object they refer to is deallocated, the reference becomes nil. As such, they are optional types.
  • Unowned references should be used when the closure and the object it refers to will always have the same lifetime as one another and will be deallocated at the same time. An unowned reference can never become nil.

To fix this strong reference cycle, add a capture list to the heartToggleHandler like this:

cell.heartToggleHandler = { [weak self] isStarred in
  self?.collectionView.reloadItems(at: [indexPath])
}

Declaring self as weak means that the SearchResultsViewController can be deallocated even though the collection view cells hold a reference to it, as they are now just weak references. And deallocating the SearchResultsViewController will deallocate its collection view, and in turn, the cells.

From within Xcode, use ⌘+I again to build and run the app in Instruments.

Look at the app again in Instruments using the Allocations instrument as you did before (remember to filter the results down to show only the classes that are part of the starter project). Perform a search, navigate into the results, and back again. You should see that the SearchResultsViewController and its cells are now deallocated when you navigate back. They show transient instances, but no persistent ones.

XCode Instruments with Swift