NEW: Learn to build the incredible iOS 15 Weather app today! >>

How to create and use protocol extensions

Paul Hudson    @twostraws   

Updated for Xcode 13.2

Protocols let us define contracts that conforming types must adhere to, and extensions let us add functionality to existing types. But what would happen if we could write extensions on protocols?

Well, wonder no more because Swift supports exactly this using the aptly named protocol extensions: we can extend a whole protocol to add method implementations, meaning that any types conforming to that protocol get those methods.

Let’s start with a trivial example. It’s very common to write a condition checking whether an array has any values in, like this:

let guests = ["Mario", "Luigi", "Peach"]

if guests.isEmpty == false {
    print("Guest count: \(guests.count)")
}

Some people prefer to use the Boolean ! operator, like this:

if !guests.isEmpty {
    print("Guest count: \(guests.count)")
}

I’m not really a big fan of either of those approaches, because they just don’t read naturally to me “if not some array is empty”?

We can fix this with a really simple extension for Array, like this:

extension Array {
    var isNotEmpty: Bool {
        isEmpty == false
    }
}

Tip: Xcode’s playgrounds run their code from top to bottom, so make sure you put that extension before where it’s used.

Now we can write code that I think is easier to understand:

if guests.isNotEmpty {
    print("Guest count: \(guests.count)")
}

But we can do better. You see, we just added isNotEmpty to arrays, but what about sets and dictionaries? Sure, we could repeat ourself and copy the code into extensions for those, but there’s a better solution: Array, Set, and Dictionary all conform to a built-in protocol called Collection, through which they get functionality such as contains(), sorted(), reversed(), and more.

This is important, because Collection is also what requires the isEmpty property to exist. So, if we write an extension on Collection, we can still access isEmpty because it’s required. This means we can change Array to Collection in our code to get this:

extension Collection {
    var isNotEmpty: Bool {
        isEmpty == false
    }
}

With that one word change in place, we can now use isNotEmpty on arrays, sets, and dictionaries, as well as any other types that conform to Collection. Believe it or not, that tiny extension exists in thousands of Swift projects because so many other people find it easier to read.

More importantly, by extending the protocol we’re adding functionality that would otherwise need to be done inside individual structs. This is really powerful, and leads to a technique Apple calls protocol-oriented programming – we can list some required methods in a protocol, then add default implementations of those inside a protocol extension. All conforming types then get to use those default implementations, or provide their own as needed.

For example, if we had a protocol like this one:

protocol Person {
    var name: String { get }
    func sayHello()
}

That means all conforming types must add a sayHello() method, but we can also add a default implementation of that as an extension like this:

extension Person {
    func sayHello() {
        print("Hi, I'm \(name)")
    }
}

And now conforming types can add their own sayHello() method if they want, but they don’t need to – they can always rely on the one provided inside our protocol extension.

So, we could create an employee without the sayHello() method:

struct Employee: Person {
    let name: String
}

But because it conforms to Person, we could use the default implementation we provided in our extension:

let taylor = Employee(name: "Taylor Swift")
taylor.sayHello()

Swift uses protocol extensions a lot, but honestly you don’t need to understand them in great detail just yet – you can build fantastic apps without ever using a protocol extension. At this point you know they exist and that’s enough!

Hacking with Swift is sponsored by Essential Developer

SPONSORED Learn the most up-to-date techniques and strategies for testing new and legacy Swift code in this free practical course for iOS devs who want to become complete Senior iOS Developers.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 5.0/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.