Four Clever Uses of Swift Extensions

If you're reading this, then I assume you're familiar with Swift extensions. A Swift extension allows you to add functionality to a type, that is, a class, a structure, an enumeration, or a protocol. But extensions are more powerful than that. In this tutorial, I'd like to show you four clever uses of Swift extensions.

Protocol Conformance

The Swift Programming Language mentions that extensions can be used to conform an existing type to a protocol. While this isn't new or revolutionary, it can also help you keep your code organized.

Take the UITableViewDataSource and UITableViewDelegate protocols as an example. This code snippet may look familiar. This is fine, but it results in a lengthy class implementation that can become difficult to navigate over time.

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    ...

}

You can keep your code organized by creating an extension for each protocol the type conforms to.

import UIKit

class ViewController: UIViewController {

    ...

}

extension ViewController: UITableViewDataSource {

    ...

}

extension ViewController: UITableViewDelegate {

    ...

}

Navigating source files also becomes easier using the jump bar.

Navigating source files also becomes easier using the jump bar.

Preserving Initializers

I learned the next trick from Chris Eidhof. For this example, we first need to define a structure, Person. The structure defines two constant properties of type String, first and last.

struct Person {

    // MARK: - Properties

    let first: String
    let last: String

}

Swift generously creates an initializer for us, init(first:last:), which we can use to instantiate an instance of the Person structure. This isn't new.

let john = Person(first: "John", last: "Doe")

Unfortunately, the initializer is no longer available if we define a custom initializer in the struct's definition.

struct Person {

    // MARK: - Properties

    let first: String
    let last: String

    // MARK: - Initialization

    init(dictionary: [String: String]) {
        self.first = dictionary["first"] ?? "John"
        self.last = dictionary["last"] ?? "Doe"
    }

}

The initializer is no longer available if we define a custom initializer in the structure definition.

Fortunately, we have an easy workaround for this issue. We create an extension for the Person struct in which we define the custom initializer.

struct Person {

    // MARK: - Properties

    let first: String
    let last: String

}

extension Person {

    // MARK: - Initialization

    init(dictionary: [String: String]) {
        self.first = dictionary["first"] ?? "John"
        self.last = dictionary["last"] ?? "Doe"
    }

}

An extension solves the problem.

Code Separation

We can take the previous example one step further. Last year, Natasha Murashev outlined a technique that uses extensions to separate state from behavior. If we apply this technique to the previous example, we end up with something like this.

struct Person {

    // MARK: - Properties

    let first: String
    let last: String

}

extension Person {

    // MARK: - Initialization

    init(dictionary: [String: String]) {
        self.first = dictionary["first"] ?? "John"
        self.last = dictionary["last"] ?? "Doe"
    }

    // MARK: - Public API

    var asDictionary: [String: String] {
        return [ "first": first,
                 "last": last ]
    }

}

The type definition only defines the stored properties. An extension is created for the behavior of the type, methods and computed properties. The result is a clear separation of state (stored properties) and behavior (methods and computed properties).

We can take this one step further by creating a second private extension for private behavior.

struct Person {

    // MARK: - Properties

    let first: String
    let last: String

}

extension Person {

    ...

}

private extension Person {

    ...

}

Code separation and organization is very easy to do using extensions. I use it all the time.

Nested Types

The Swift Programming Language mentions that extensions also allow you to define and use nested types. But I feel this feature is undervalued. I use it in every Swift project, for example, to define constants.

A week ago, I wrote a tutorial about building a custom control using a bitmask. In that tutorial, we stored the raw value of the bitmask in the user defaults database.

// MARK: - Actions

@IBAction func scheduleDidChange(_ sender: SchedulePicker) {
    // Helpers
    let userDefaults = UserDefaults.standard

    // Store Value
    let scheduleRawValue = sender.schedule.rawValue
    userDefaults.set(scheduleRawValue, forKey: UserDefaults.Keys.schedule)
}

Instead of using a string literal, we used a constant. We created an extension for the UserDefaults class in which we defined an enum without cases, Keys. The enum defined one static constant property of type String.

extension UserDefaults {

    enum Keys {

        static let schedule = "schedule"

    }

}

The result is quite nice if you ask me. Not only can we group constants, avoiding literals scattered throughout the codebase, we also namespace the constants. In other words, the constants are easy to remember and make sense.

UserDefaults.Keys.schedule

This technique has also been adopted by several Apple frameworks with the release of Swift 3.

Notification.Name.UIApplicationWillTerminate

Stop Writing Swift That Sucks

Download the Swift Patterns I Swear By

About Bart Jacobs

About bart jacobs

My name is Bart Jacobs and I run a mobile development company, Code Foundry. I've been programming for more than fifteen years, focusing on Cocoa development soon after the introduction of the iPhone in 2007.

Stop Writing Swift That Sucks

In my free book, you learn the four patterns I use in every Swift project I work on. You learn how easy it is to integrate these patterns in any Swift project.