Protocol-Oriented Programming For Fun And Profit

I've been wanting to get my feet wet with protocol-oriented programming for a while now. The difficulty lay in the fact that the app I write is a mismash of old and new, Objective-C and Swift. Protocol-oriented programming seems to really like having a Swift-only environment. So I decided to throw out reality for a few hours and decide how I would architect the model layer of the app if I were starting from scratch today.

It was an brain-tingling prospect. All Swift! Protocols! Generics! Non-Int Enums! I'll never go back, I can't! I won't!

I started with my model collection. The Collection class was one of the oldest classes in the app and while it had been re-written in Swift, it was mostly a straight port without taking advantage of much Swift-specific coolness.

class Collection {
      private(set) var models: [ModelType]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func add(model: ModelType)
      func remove(model: ModelType)
      func destroy(model: ModelType)
      func commit()
      func fetch()
      func sort()
}

There was a lot more to it, but this would do to start. The Collection class was a similar concept to the NSManagedObjectContext that you get with CoreData. It held models, fetched model data from the data source and committed changes to the models back to the data source. In this brave new world of Swiftitude, I knew I wanted to rewrite this class with one feature in particular: generics.

class Collection<T: ModelType> {
      private(set) var models: [T]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func add(model: T)
      func remove(model: T)
      func destroy(model: T)
      func commit()
      func fetch()
      func sort()  
}

You smell that, kids? Smells like the future.

This let the compiler know that I'm going to be throwing all kinds of stuff in there. I constrained it to ModelType because I knew that, realistically, it was only going to be things adhereing to the ModelType protocol that I was going to put in there. I did have a moment of "well, what does this even get me?" But stay tuned, there's more.

I was going to start fleshing out the methods, when the Swift Spirit whispered in my ear, "Use the protocols...".

I wondered how, or why and then I remembered there was a very good business reason for using protocols on my Collection class. There were models that the user could mutate and save those changes back to the DataSource, but there were others should not be edited by the user, but were still fetched into the Collection. These models didn't need the mutating functions like commit() and, in fact, shouldn't have them.

And thus a protocol was born.

I fired up a new .swift file and named the new protocol Persistable.

protocol Persistable {
    // Some model-specific mutating features go here
}

Now, I could have some of my models be persistable to the DataSource while others would be essentially read-only. I went back to my Collection and pulled the mutating functions into their own extension.

class Collection<T: ModelType> {
      private(set) var models: [T]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func fetch()
      func sort()  
}

extension Collection where T: Persistable {
      func add(model: T)
      func remove(model: T)
      func destroy(model: T)
      func commit()  
}

Cool, cool. Now all of the functions that changed the collection once it had been loaded from the database would only be available if the models it contains are Persistable.

That was it; I had the need, the need for refactoring class functionality into protocols and extensions.

The sort function wasn't just a simple sort, but a sort that was based in business logic. Each model communicated to the Collection what its sort capabilities were. Some models, however, were simply back-end data that didn't really need to be sorted at all. ⌘-N

protocol Sortable {
    // Some model-specific sort methods go here
}

⌘-SHIFT-O File Name: Collection.swift

class Collection<T: ModelType> {
      private(set) var models: [T]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func fetch()
}

extension Collection where T: Persistable {
      func add(model: T)
      func remove(model: T)
      func destroy(model: T)
      func commit()  
}

extension Collection where T: Sortable {
      func sort()  
}

Extensions can't hold stored properties, so sortDefinition had to stay in the main class implementation, but sort() got its own little home and would only be available if the models in the Collection were sortable.

Not only was protocol-oriented programming a new way of doing things, but it could acutally be useful. If commit() wasn't popping up in my code completion for a Collection, it would spur me to remember that that model shouldn't (and now, couldn't) be edited. The core of the class was lean and methods were organized in a logical manner instead of one mega-class definition that does All The Things.

I had to return to reality, but I made sure to save my project. This wouldn't be the last time I would visit this Swift-only fantasy land...


You Really Should Be Using flatMap

Most high-level languages have some variation of map, reduce and filter and Swift is no different. These functions operate on arrays to turn them into something else that is more useful to you. For example, map is used to iterate over an array and, for each value, return another value derived from it. For example:

let arrayOfNumbers = [3, 12, 5, 2]
let arrayByAddingTwo = arrayOfNumbers.map { (number) -> Int in
    return number + 2
}

// arrayByAddingTwo is now [5, 14, 7, 4]

Okay, so a function that adds two to an array of numbers may not be all that useful, but you can probably see how a function that iterates over an array and transforms it into values in another array can be useful. You probably do something similar all of the time.

“But wait”, you say, “can’t we just do this with a for in loop?” Right you are, astute reader.

let arrayOfNumbers = [3, 12, 5, 2]
var arrayByAddingTwo = Int
for num in arrayOfNumbers {
    arrayByAddingTwo.append(num+2)  
}

// arrayByAddingTwo is now [5, 14, 7, 4]

“See? Why do we need this whole other thing when we can just build an array with an existing control flow structure?”

While it may look like the end result is the same, there is one subtle difference. In the first example, arrayByAddingTwo is immutable, while in the second, it is mutable.

And remember, Swift really likes things to be immutable as much as possible. Now, of course, you could just copy the mutable arrayByAddingTwo into an immutable array, but by that point, we’re making an already longer block of code even longer. Functions like map increase readability by focusing on the task at hand (in this case, adding two to a number) instead of mucking about with boilerplate.

And with Swift’s shortened syntax, we can make this code even shorter:

let arrayOfNumbers = [3, 12, 5, 2]
let arrayByAddingTwo = arrayOfNumbers.map { $0 + 2 }

// arrayByAddingTwo is now [5, 14, 7, 4]

Two lines. Awesome. I mean, is it really necessary to have 5+ lines of code for just adding two to an array? I assert that, no.

The other functions, reduce and filter are used similarly. reduce coalesces an array into a single, immutable, value and filter returns an immutable array with a subset of the given array. I’ll leave those as a research exercise for the reader, because what’s really interesting is flatMap.

Whenever you get a new hammer, everything starts looking like nails, even screws. -The Internet

Yeah, but flatMap is a really good hammer. -Me

So what does flatMap do? It coalesces multi-dimensional arrays into a single dimension.

😐

“That’s it?” you are surely saying. “That’s the magical flatMap.” Sure, when I say it that way, it sounds kind of lame. But this great post by Natasha the Robot points out that is less about coalescing arrays as much as it is about coalescing containers of values. We’ll see why this is a big deal in a moment.

So, let’s take the multi-dimensional array:

let multiDimensional = [[1,2], [3,4], [5, 6]]

It’s a little awkward for what we want. It’d be better if it were just an array of numbers. flatMap can help with that.

let singleDimension = multiDimensional.flatMap { (subArray)
    return subArray
}

flatMap will unwrap those sub-arrays and line up everything in a nice, immutable array of Ints like so:

 // singleDimension is now [1,2,3,4,5,6]

We could have used it like a map as well, transforming the values as they were being unwrapped.

“I mean, yeah, that’s cool and all, but far from magical,” you say.

We’re not done with flatMap yet.

So, lets look at this situation:

let imagesNames = ["image1", "image2", "image3"]
let images = imageNames.map { (imageName) -> UIImage? in
    return UIImage(named:imageName)
}

// images is an array of type UIImage?

This map function transforms our array of image names that reference images in our asset library and returns an array of images…sort of. UIImage(named:) is a fail-able initializer, which means it doesn’t return an UIImage, it returns a UIImage? which may be nil. Now, this may be fine, but we probably want an array of UIImage, which means we’ll have to add a bit more code.

let justImages = images.filter { (image) -> Bool
    return image != nil    // Only returns the UIImages
} as! [UIImage]

Now we’ve filtered out all of the UIImage optionals that are really just nil and we are left with those that really have a UIImage in them. We can then force cast the array to [UIImage] since we know we’ve removed all of the nils.

If that bang makes you a little nervous, it should. It’s not very Swifty and even though we know it’s safe to do what we’ve done, there is a better way.

You guessed it, flatMap. Now it’d seem like flatMap has nothing to do with this situation. This is a single dimension array of optionals, not a multidimensional array, but remember what we said about flatMap working on collections. What is optional, really, but a collection that contains at most one value.

Yep, flatMap can unwrap optionals.

Let’s redo the code from above using flatMap:

let imagesNames = ["image1", "image2", "image3"]
let images = imageNames.flatMap { (imageName) -> UIImage? in
    return UIImage(named:imageName)
}

// images is of type [UIImage]

We just plopped that flatMap and it did the work of unwrapping those optionals, giving us a nice, clean array of UIImages. Magic.

Look around your code. Especially if you deal with JSON data from a web server or data entered by the user, you probably have collections with optionals everywhere. flatMap can help you strip out those optionals and give you clean, immutable typed arrays that are much easier to work with.


Fun With Iterations in Swift

One of the things I love about Swift is that it really tries to get some of the boilerplate out if the way. This doesn't seem true when you write your first optional unwrapping, of course. Something like optional unwrapping doesn't seem like a big deal at first, but once you've written your 100th variation on:

if let unwrapped = optionalVariable as? String {
    //do something
}

Things seem to be a lot more wordy. I mean, you get it, Swift sort enforces safety, but dealing with those safety checks can start to feel tedious.

Enter Swift's desire to get ride of the uninteresting parts of your code. Take the humble for-in loop that we all know and love, for example.

for myString in stringArray {
    //do something
}

Seems reasonable enough, but let's assume that, instead of and array of String, we're dealing with an Array of AnyObject? and we want to print "found it" anytime we find an occurrence of 🍉 in our array.

"Not a problem," you think to yourself. First we have to iterate over the array, unwrap the optional while casting to a string, then checking to see if the string matches 🍉.

We'll probably end up with something like this:

for thing in watermelonPatch {
    if let possibleMelon = thing as? String {
        if possibleMelon == 🍉 {
            print("found it!)
        }
    }
}

Now, there isn't anything wrong with this code per se, but taking up a lot of visual space setting up for the one line where we actually do something, which is print("found it!). Everything else is pretty much just checking to see if all of the conditions are right to execute this line.

Let's refactor this loop to put emphasis on the part that's the most important. The first thing we'll do is move our condition check up into our optional unwrapping line.

for thing in watermelonPatch {
    if let possibleMelon = thing as? String where possibleMelon==🍉 {
        print("found it!)
    }
}

Nice. Looking better already. Swift's whereis incredible useful. You can use it in unwrapping statements like the above code or you can use it to add conditional checking to switch statements.

Speaking of switches, we can use the pattern matching you often see in switch statements to do our optional unwrapping in the for loop itself. Behold:

for case let possibleMelon as String in watermelonPatch where possibleMelon == 🍉 {
    print("found a watermelon!")
}

We've gone from 7 lines down to three and removed all of the nested bracketed statements. Now, the important work of announcing that the watermelon has been found isn't being lost in all of the conditional code around it.

Now, like everything, this could be carried too far. If we are inadvertently obscuring important code in our boilerplate reduction, we aren't gaining readability, which is the goal here. In the end, we are trying to help people who are reading the code to focus on the most important parts, rather than getting lost in setup code and boiler plate.


A Quick(ish) Guide to Gzipping for iOS Apps

Compressing HTTP content has been around forever. Still, it can be common for the traffic between our apps and our web api to not be gzipped. For some apps, this isn't a big deal as the payload between the app and the server is quite small, pehaps just a couple KBs of JSON or XML. For other apps, however, gzipping can make a big difference in the amount of time it takes to communicate with the server.

First, we'll quickly discuss HTTP compression generally. The most common options when it comes to compressing HTTP content are deflate, gzip, and sdch. The first option, deflate, is a is a close cousin of gzip, but there are some browsers (cough IE cough) that didn't implement deflate correctly, so it fell out of favor. The last one, sdch, is a proprietary Google algorithm that is supported natively in Android and Chrome. Since we're dealing in iOS apps, this isn't really going to work for us, either.

This leaves the stalwart ole gzip. Gzip is supported out-of-the box in NSURLSession and automatically communicates to network servers that it can handle gzipped data. When the server sends down gzipped data, NSURLSession automatically de-compresses it; you don't have to do anything. This is awesome, except that all of this automatic-ness can require a bit of hacking in some situations, which we will get to in a minute.

Not all network traffic is ideally suited for gzipping. PDFs and most image formats are already compressed and gzipping them isn't going to make the files any smaller. Small files also aren't ideally suited for gzipping as they can actually get slightly larger with the overhead of the compression dictionary. Gzipping works really really well on text-based data. If your web API deals in moderate-to-large sized chunks of uncompressed or text-based data, gzip can really make your network payloads smaller. You can algorithmically determine if your server should gzip a specific payload, or you could just gzip everything. Google tends to advocate gzipping all traffic since the gains made for most payloads outweigh the negligible CPU costs of decompressing and even some images may benefit from gzipping as they can sometimes have a fair amount of metadata that can be compressed. Google has an interesting article on HTTP compression.

Is Gzipping Worth It?

I ran a couple of tests using some sample data. One example was a SQLite database file while the other was straight JSON.

File Type Data Size Gzipped Size
SQLite database 15 MB 2.7 MB
JSON Data 234KB 11KB

For the SQLite file, we have about an 80% smaller file and for the JSON data, we're looking at around a 95% savings. That's huge. Or small. Whatever. Obviously, the results will vary by the data you throw in to gzip, but for the data that it is well suited, gzipping is well worth it.

How Do I Make This Happen?

On the server

Apache, the most common web server, allows you to turn on http compression via its .htaccess files. This is great, but if turning on gzipping globally isn't an option, we can enable it on a per-request basis.

I'm going to use PHP and JSON for these examples.

Clients and servers let each other know their gzip capability via HTTP headers. The specific header is Accept-Encoding: gzip. NSURLSession sends this header to servers by default, so we don't have to do anything there. On the server side, we'll have to get our hands a bit dirty.

In the PHP file that our app is communicating with, we likely have some version of this:

echo json_ecode($data);
exit;

This outputs our JSON-encoded data which is sent down to the app. Great. We've decided that we want to gzip this output. To do so, first we need to get a little PHP-specific.

PHP has what are called output buffers. Unless output buffering is turned off, everything echoed out is kept in a variable (a buffer) until the end of the script, then the data is output all at once. To keep things simple, we want to gzip our entire output, so we need to clear out anything that's already in the output buffer.

We'll jump up a couple of lines and add some code.

while(ob_get_level())
{
    ob_end_clean();  
}

Output buffers can be nested, so we need to loop through and make sure that we "clean" all of the output buffers that may exist at the moment. Unless we've been echoing out data further up in the code, this is probably unnecessary, but better safe than sorry.

Now we'll alter our json_encode code from above.

// Create a json encoded string
$json = json_encode($data);         
// Get the uncompressed size.
$size = strlen($json);
// Gzip the string.
$compressed = gzencode($json);      
// Tell the app that the response is gzipped
header('Content-Encoding: gzip');   
// Send the uncompressed content length (we'll get to this in a moment)
header('X-Uncompressed-Content-Length: ' . $size);  
// Send the compressed content length
header('Content-Length: ' . strlen($compressed));   
// Output the gzipped data.
echo $compressed;                   
exit;                               
// We're done. 😌

That's it as far as the server goes. See that header('X-Uncompressed-Content-Length: ' . $size) bit? That's our hack for progress reporting.

App Code

Since we've converted all of our network code over to NSURLSession from NSURLConnection (right?!?), we'll use NSURLSession for this example.

As we discussed before, NSURLSession handles all of the decompression for us. Awesome. Except it needs to back off and give us a little emotional space because it's trying too hard and it is getting in the way of progress.

Download progress specifically.

🙄

Here is the delegate method that we all know and love that gets called when we get a response from the server.

func URLSession(_ session: NSURLSession, dataTask dataTask: NSURLSessionDataTask, didReceiveData data: NSData)

There's a lot of interesting objects in there. We know that we can grab that dataTask and check its countOfBytesReceived property and we divide it by its countOfBytesExpectedToReceive and we have the progress percent.

Except.

With gzipped content, NSURLSession will always report countOfBytesExpectedToReceive as -1. Also, the countOfBytesReceived is the uncompressed count, not the actual number of bytes transmitted to the app. 😒 It really tries to hide the compression from you.

This is where our header hack comes into play. Server headers that start with X- are user-defined, non-standard headers. We sneaked the uncompressed download size into the header so we can make this the body of our delegate method.

 if let response = downloadTask.response as? NSHTTPURLResponse,
    let contentLengthString = response.allHeaderFields["X-Uncompressed-Content-Length"] as? String,
    let contentLength = Int64(contentLengthString) {
                print("Download: \(totalBytesWritten)/\(contentLength)")
        }

First we cast our response as a NSHTTPURLResponse (geez, that name) and we grab our uncompressed content length from the header. We then convert it to an Int64 and divide the downloaded count from the delegate for our uncompressed total.

And 👏🏾, data transfer progress of gzipped data in our Swift app. Greatly reduced traffic. Faster downloads. Win/win/win.


Default Implementations, Swift, and Objective-C

Since WWDC we've been made well aware that Swift wants you to protocol all of the things. This is extremely useful when using a Swift project. When incrementally converting a project that has both Swift and Objective-C, adopting these very Swifty conventions can be more difficult.

Protocol Extensions

Protocol extensions are, among other things, a way to provide a default implementation to a protocol method.

protocol MyProtocol {
    func myMethod()
}

This defines a protocol (MyProtocol) and defines a protocol method, myMethod(). Classes that implement this protocol must provide an implementation of myMethod(). That's essentially what protocols are.

A protocol extension allows you to define a default implementation of an protocol method.

extension MyProtocol {
    func myMethod(){
        print("Default implementation!")
    }
}

Cool. Now classes (and structs) implementing this protocol can either implement their own implementation of myMethod(), or they can rely on the default implementation. Protocol extensions are a main reason why protocols are so powerful in Swift.

The Objective-C Wet Blanket

Objective-C has protocols as well. It can even use Swift protocols (well, at least those that are marked with the objc attribute). What it can't do, however, is use those default implementations declared in protocol extensions. To Objective-C, protocols are just a map to the messages an object can or cannot receive. It doesn't get the concept of default implementations. So what do you do if you need to work with Objective-C, but want default implementations?

In this case, we can adopt a pattern that Objective-C itself uses for NSObject. It's not exactly pretty and requires class inheritence, which is something we were trying to get away from with protocols, but it works and can be used as a stop-gap measure until we've refactored out the last of the Objective-C from our apps.

Objective-C has an object called NSObject. This is no surprise as almost every class in Cocoa and our own apps subclass NSObject. However, you don't have to subclass NSObject in order to to play nice with Cocoa which really, really likes NSObject. What you have to do instead, is adhere to the NSObject protocol. So, NSObject is both a class and a protocol in Objective-C. There are even some classes in Cocoa, such as NSProxy that take this approach.

The NSObject protocol defines methods like isEqual:, hash, isKindOfClass and many others.. Ninety-nine percent of the time, you'll simply want to subclass NSObject so you won't have to implement all of these classes yourself; you can just rely on the, wait for it, default implementation.

You can probably see where I am going with this.

A Protocol By Any Other Name

So, let's say with the protocol we defined above, MyProtocol, we want to use default implementations in Swift and Objective-C. In order to accomplish this, we'll need to define our protocol in Objective-C, not Swift. Let's also change the name to MyObject while we're at it, since it will make more sense in this situation.

@protocol MyObject
- (void)myMethod;  
@end

Now, in order to define our default implementation, we'll create a class with the same name.

// MyObject.h
@interface MyObject: NSObject
- (void)myMethod;
@end

// MyObject.m
@implementation MyObject
- (void)myMethod 
{
    NSLog(@"Default implementation!");  
}  
@end

Now we have a protocol and a default implementation. To use this in an Objective-C class, we now do this:

@interface CoolObject: MyObject
@end

CoolObject both subclasses MyObject and conforms to the MyObject protocol. It can rely on myMethod defined in the class or it can define its own.

So what is the advantage of this over straight subclassing? Let's see how we implement this in Swift to see.

MyObject and MyObjectProtocol

Swift won't let you have a protocol and a class with the same name. This isn't a problem, it'll just just tack on "Protocol" to the name of the protocol in question in order to distinguish the two. (It imports NSObject as NSObject and NSObjectProtocol.)

Since we have MyObject and MyObjectProtocol to work with, we can either conform to MyObjectProtocol and implement our own myMethod or we can additionally subclass MyObject in order to get the default implementation. Our app passes around the MyObjectProtocol definition, which is super Swifty and our classes can either be MyObject subclasses or not.

No, it isn't as good as protocol extensions as it still requires subclassing which is oh-so-not-Swifty, but when playing in the sandbox with Objective-C and Swift, we sometimes have to make some compromises in order to have Objective-C know what's going on and keeping the compiler happy. It's not perfect, but it gives us optional default implementations in both Objective-C and Swift until the day we can sweep Objective-C out the door of our app entirely.