Practical Protocol-Oriented Swift

In the beginning Swift protocols felt a bit off when compared to protocols in Objective-C. The fact that I can easily declare an optional method in Objective-C with

is one of many examples. Even though there is a way to somewhat replicate that same behavior in Swift by prepending @objc in front of your protocol declaration, the entire idea of having @objc inside of your Swift class is somewhat weird to me personally. Not that there is anything wrong with it since Swift is using Objective-C runtime anyway.

Swift is a Protocol-Oriented programming language and until Swift 2.0 it was a bit unclear how that really played into a greater scheme of things. However, after the announcement of Swift 2.0 and the ability to extend protocols in Swift 2.0, it became much clearer.

So let’s get the obvious out of the way first… how do protocol extensions differ from base classes? First of all, inheritance is restricted to class types only, which means structs are out of luck. But what if you need to use structs to define your model? Since structs are first class citizens in Swift, you can use them to do just that. Apple talks about classes and structs in their article here. The caveat is that you can’t subclass them… you do get other benefits though such as having them copied when passing around vs classes that are passed by reference.

On the other hand classes, structs, and even enums can conform to multiple protocols that require specific implementation (UITableViewDelegate, UITableViewDataSource) without introducing a state – default implementation that comes with a base class.

Circling back to the idea of @optional methods… with protocol extensions in Swift 2.0, we can simply extend a protocol methods with default implementation. Let’s look at some examples of where the Protocol-Oriented programing would be a great fit.

Let’s assume we are building an API client. There are many ways to approach this but for arguments sake assume we have a base class called APIRequest:

The idea is to subclass APIRequest and override functions with specific url, method, headers or queryString. The next step would be to extend NSMutableURLRequest to take an instance of APIRequest and create a valid NSMutableURLRequest like so:

The final piece is to build a generic enqueue function in our API class that would simply execute the NSMutableURLRequest request and serialize data into valid JSON objects like this:

Subclassing works in this case without issues. However, if we wanted to use structs, we would be out of luck completely since they don’t support subclassing. A much better approach would be to use protocols to define methods and have each subsequent class / struct conforming to APIRequest protocol implement the requirements. Very flexible and allows for greater abstraction. So let’s rewrite this same implementation using the Protocol-Oriented approach.

The idea is that you always start with protocols, not classes. In light of this revelation, lets declare a new protocol called APIRequest and extend (protocol extension says, all models of this protocol have this default implementation) it:

Next, let’s implement a sample GETRepositories request to GitHub API like so:

While the implementation is almost identical, the HUGE difference is that our GETRepositories request is a struct plus it has no base class. The behavior is defined by a protocol. This is just so freaking cool. When I think about Swift in general, I can see and appreciate the direction that it’s taking. Writing software that’s modular and can be reused is such a time saver.

I would recommend watching Apple’s vide on Protocol Oriented Programing from this years WWDC. Great stuff.

Practical Protocol-Oriented Swift

One thought on “Practical Protocol-Oriented Swift

Leave a Reply

Your email address will not be published. Required fields are marked *