So, if you’re using a class, structure, or enumeration which did not provide a method that would be very helpful for your app, you could simply add it via an extension (which you can read more about in the posts Swift Extensions Part 1, and Swift Extensions Part 2). With extensions, you can easily add methods to a type that builds upon the existing types. One of my favorites is writing my own UIColor convenience initializer (shown in the post How to Create a UIColor in Swift), that takes a value between 0 and 255, and hardcodes the alpha to 100% opacity. I definitely understand why the authors did it the way they did, it is general so you can do many things with it, but I didn’t want the boilerplate required to convert my 0-255 based RGB values, and I CERTAINLY didn’t want to set the alpha to 100% each time when it would never be anything else in my app.
Well, that’s great and all for classes, structures, and enumerations…. but what about protocols? In Swift 1, you could write your own protocol and have methods in it that would then have to be implemented by those types that adopt the protocol… but if it doesn’t have a method you need, the only thing you could do was either write an extension for each type that adopted the protocol, or write it as a global function. That’s exactly what Apple did for a lot of functions in Swift 1, particularly many that worked with several CollectionTypes like Arrays, Dictionaries, and Sets.
With the coming of Swift 2 though, we now have a recourse that no longer requires global functions. Now you CAN extend protocols with Protocol Extensions. You can even provide default implementations for these methods defined in those protocol extensions!
Defining and Conforming to a Protocol
So let’s say that we have a protocol to describe that something 2-dimensional can be moved by a certain amount, it might look something like this:
protocol TwoDMovable { mutating func relativeMove(x: Int, y: Int) }
All it has is a mutating function that will move whatever this is over in the X-axis by x amount, and in the y-axis by the y amount. Pretty Simple. Now let’s make something that adopts and conforms to this protocol:
struct myPoint: TwoDMovable { var x: Int var y: Int mutating func relativeMove(x: Int, y: Int) { self.x += x self.y += y } }
It’s just a simple point that has an X and a Y coordinate, and then gives that protocol’s function prototype an actual implementation, which just adds the amounts in the parameters to internal coordinates.
Simple enough. But what if, like my UIColor extension mentioned earlier, an app used a few types that adopt this protocol, but we only ever needed to move it in the X direction. You would have to just set the y movement to 0 each time. While that isn’t hard, it can be annoying if you NEVER use it, and it leaves you open to making errors if you accidentally type a number there.
Adding Protocol Extensions to an Existing Protocol
With protocol extensions in Swift, we can just add something that moves it only in the X direction. In this case, I am defining the positive X to be to the right, which is usually the case in iOS and Mac programming:
extension TwoDMovable { mutating func moveToTheRight(amount: Int) { relativeMove(x: amount, y: 0) } }
You make a protocol extension just like you would make an extension for any normal type, just type “extensions” and then the name of the protocol you want to make the protocol extension for. So now we can use it like we would any other function:
//Make a mutable myPoint entity var somePoint = myPoint(x: 5, y: 7) // somePoint created at (5,7) somePoint.moveToTheRight(amount: 4) // somePoint now at (9,7)
Now you also see that there is a default implementation in there. If the type implements its own version in itself or another extension, that version will be used instead of the default one here. This one didn’t need to know anything about the internals like the names of where the X and Y values are stored, it just needed to take advantage of the moveToTheRight method that was listed in the original protocol.
Adopt the Extended Protocol, Get the Protocol Extension Free
So, that means if we create something else like a circle with a center and a radius like this:
struct myCircle: TwoDMovable { var centerX: Int var centerY: Int var radius: Int mutating func relativeMove(x: Int, y: Int) { centerX += x centerY += y } }
We automatically have that implementation of moveToTheRight, since myCircle implemented the relativeMove(X:Y:) method. So the method in our protocol extension can be used the same as it was in myPoint:
//Make a mutable myCircle entity var someCircle = myCircle(centerX: 2, centerY: 14, radius: 5) //someCircle created at (2, 14) someCircle.moveToTheRight(amount: 5) //someCircle now at (7, 14)
Conclusion
With the addition of protocol extensions back in Swift 2, all named types (classes, structures, enumerations, and protocols) can be extended, giving them more capability than they were originally written with. This post has just gotten into the mechanics of creating and using protocol extensions. Later on we’ll cover the aspects of Protocol Oriented Programming mentioned at WWDC 2015, but I’m still wrapping my mind around it like so many others. You can watch the session about it on the Apple Developer portal (that no longer requires a login!) at Protocol-Oriented Programming in Swift.
I hope you found this article helpful. If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps. Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do. Thanks!