NEW: Master Swift design patterns with my latest book! >>

< Previous: Setting up   Next: Protocol-oriented programming for beginners >

Creating a Swift extension

I've been asking you to use a file called Helper.swift several times so far in this series, and it's basically a collection of interesting functions that do a handful of difficult tasks. However, that file is messy: it has function names like RandomCGFloat() and RandomColor() mixed together even though they do quite different things.

This gets confusing. It gets confusing because we don't know where these functions come from, it gets confusing because we're filling the code completion database with global functions that have similar names, and it gets confusing because these functions don't all take uniform parameters. Extensions can help us fix the first two, because it lets us move these global functions to be methods inside a class or struct.

We're going to start with an extremely simple extension so you can get a basic grip on how things work before moving on to more complicated examples.

Let's start with an extension that adds one to an integer. Yes, I realize this is essentially just += 1, but we're starting simple. Put this in your playground:

import UIKit

var myInt = 0

This code will be evaluated immediately, so in the right column you'll see 0. This tells you that the myInt variable has the value 0. Now add this to the playground, just beneath the import UIKit statement:

extension Int {
    func plusOne() -> Int {
        return self + 1
    }
}

There are two things in there that are new:

  1. extension Int tells Swift that we want to add functionality to its Int struct. We could have used String, Array, UIButton or whatever instead, but Int is a nice easy one to start.
  2. self + 1 is new because so far we've only used self to refer to a view controller or SpriteKit scene. Well, self in this case refers to the number that was used to call this method.

How the extension works will become clear once you use it. Put this line just below the current myInt line:

myInt.plusOne()

In the right column you'll now see 0 for the first line and 1 for the second, so calling plusOne() has returned a number one higher than the number we called it on. Note: unlike regular Swift files, playground code is executed linearly – i.e., top to bottom. That means you need to put the extension code above where you use it.

The extension has been added to all integers, so you can even call it like this:

5.plusOne()

When you do that, you'll see 6 in the output column.

Our little extension adds 1 to its input number and returns it to the caller, but doesn't modify the original value. Try typing this:

var myInt = 10
myInt.plusOne()
myInt

Using a variable by itself tells the playground just to output its value, so in the output column you'll see 10, then 11, then 10 again. This is the original value, the return from the plusOne() method, and the original, unchanged value.

To push things a little further, let's modify the plusOne() method so that it doesn't return anything, instead modifying the instance itself – i.e., the input integer.

To make that happen, you might think we need to do something like this:

extension Int {
    func plusOne() {
        self += 1
    }
}

That removes the return value because we aren't returning anything now, and it uses the += operator to add one to self. But this won't work, and in fact Xcode will give you a wonderfully indecipherable error message: "Cannot invoke += with an argument of type Int."

That error will undoubtedly make you think, "surely += and Ints go together like George Lucas and endless Star Wars remakes," but what Xcode really means is that it Swift doesn't let you modify self inside an extension by default. The reason is that we could call plusOne() using 5.plusOne(), and clearly you can't modify the number 5 to mean something else.

So, Swift forces you to declare the method mutating, meaning that it will change its input. Change your extension to this:

extension Int {
    mutating func plusOne() {
        self += 1
    }
}

…and now the error message will go away. Once you have declared a method as being mutating, Swift knows it will change values so it won't let you use it with constants. For example:

var myInt = 10
myInt.plusOne()

let otherInt = 10
otherInt.plusOne()

The first integer will be modified correctly, but the second will fail because Swift won't let you modify constants.

Help support Hacking with Swift

This site is funded by Hacking with Swift supporters who buy my e-books. If you can, please support my work – it comes packed with bonus material!

< Previous: Setting up   Next: Protocol-oriented programming for beginners >
Click here to visit the Hacking with Swift store >>