Ulrik's Blog
@ulrikdamm

Readable code with Swift

One of the, in my opinion, best features of Swift is the update in code readability. Objective-C was always known for being very verbose, and having a very stange syntax. And even though a lot of people got really fond of it, the fact is that Objective-C code was not the best language for writing short, clear and concise code (and I’ll talk a bit about why I think these things are more important than most people probably think). With Swift, we can now say goodbye to square brackets, pointer-soups and a block syntax no one can figure out. And not only that, we now have our toolbelt filled with all kinds of new, shiny gadgets, which we should find out, how to get the best use out of.

When writing code for iOS or OS X, you’re forced to use a lot of tools that is provided for you. Some of the features provided by the system, even though the functionality might be pretty awesome, have pretty annoying, and sometimes even terrible, interfaces for using them. Still, there’s nothing preventing us from customizing them to fit our own needs. In this post, I’ll go though a few commonly used APIs in Cocoa, and explain how I’ve extended them to be more readable, by using some of the new features of Swift. It’s not meant to be a big open source library to redefine all of Apple’s APIs, but rather as an inspiration of what is possible. Some of these have drastically changed how I write code, and I hope that they will be useful to you as well.

Auto Layout API

One of the first APIs I wanted to fix with the new syntax in Swift is my least favorite API in iOS: the Auto Layout methods. Not having to use those was one of my primary reasons for using Interface Builder for laying out UIs. Let’s look at an example of setting up an Auto Layout constraint in Objective-C:

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:

view1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual

toItem:view2 attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0];

This code is pretty awful for a number of reasons. First and most important is, that just by glancing over this piece of code, you have no idea what it does. You can see that it sets up a constraint of some sort, but for knowing exactly what it does, you will have to carefully read all of it. It’s also hard to spot if there’s a mistake somewhere in it. And lastly, there’s very little of this code that is actual information, and not just annoying boilerplate. Objective-C is known for trying to making code readable by explaining everything like a sentence, but especially in this case, it’s just not working. Most views also have a lot of constraints, so imagine setting up ten constraints with this method, and the problems just become even more evident.

Swift already helps this method a bit. We can now replace NSLayoutAttributeWidth with just .Width, since it can infer the type of the enum, which reduces it to this code:

let constraint = NSLayoutConstraint(item: view1, attribute: .Width, relatedBy: .Equal, toItem: view2, attribute: .Width, multiplier: 1.0, constant: 0.0)

Already a lot easier to read, but still a lot of code to write. Let’s try to make our own wrapper method, so that we can customize it ourselves.

extension NSLayoutConstraint {

convenience init(

item1 : UIView,

attribute1 : NSLayoutAttribute,

relation : NSLayoutRelation,

item2 : UIView?,

attribute2 : NSLayoutAttribute,

constant : CGFloat,

multiplier : CGFloat) {

self.init(

    item: item1,

    attribute: attribute1,

    relatedBy: relation,

    toItem: item2,

    attribute: attribute2,

    multiplier: multiplier,

    constant: constant)

}

}

Here I’ve made an extension of NSLayoutConstraint, where I define my own convenience initializer (convenience just means that it will call an initializer on self instead of super.) right now, it’s just an exact copy on the original initializer we used before, so let’s try to improve a bit on it.

extension NSLayoutConstraint {

convenience init(

_ item1 : UIView,

_ attribute1 : NSLayoutAttribute,

_ relation : NSLayoutRelation,

_ item2 : UIView?,

_ attribute2 : NSLayoutAttribute,

_ constant : CGFloat,

_ multiplier : CGFloat) {

self.init(...)

}

}

What we’ve done here is to define a custom external name on the parameters to the method. This is the name that will be used for callers of the method, as opposed to internally in the method. We’ve set the external name to an underscore, which means that it don’t have any external name, but will only be positional. Now, using it looks like this:

NSLayoutConstraint(view1, .Width, .Equal, view2, .Width, 1.0, 0.0)

Now we’re starting to get a lot more condensed and readable. View1’s width equal to view2’s width, almost word-for-word, and even though the parameters doesn’t have descriptive names, the code is very understandable and clear. The only problem with this is the last two numbers: It’s not quite clear what these are for. Even if you know that that’s the multiplier and constant, you might not remember the order of them. This is a perfect example of when you actually want descriptive external parameter names. So let’s add them back again:

extension NSLayoutConstraint {

convenience init(

_ item1 : UIView,

_ attribute1 : NSLayoutAttribute,

_ relation : NSLayoutRelation,

_ item2 : UIView?,

_ attribute2 : NSLayoutAttribute,

constant : CGFloat,

multiplier : CGFloat) {

self.init(...)

}

}

NSLayoutConstraint(view1, .Width, .Equal, view2, .Width, constant: 1.0, multiplier: 0.0)

Perfect. Readable and short, but not confusing. It solves all our problems from before: A quick glance tells you exactly what the code does, error are easy to spot, and it has a minimal amount of boilerplate. And the only thing we’ve changed from the old API was to fix the external parameter names.

Even though, there’s still one case where this method doesn’t look as good:

NSLayoutConstraint(view1, .Width, .Equal, nil, .NotAnAttribute, constant: 100.0, multiplier: 0.0)

Here, we just want to set a fixed width on a view, and it suddenly doesn’t look as good, and the nil is quite confusing. Also the multiplier is kind of redundant; it has had a value of zero in every example so far. Luckily, these things can all be fixed by setting default parameter values. This is a way of having a default value for parameters, so that they can be omitted when unimportant. Let’s add some default parameters to our initializer:

extension NSLayoutConstraint {

convenience init(

_ item1 : UIView,

_ attribute1 : NSLayoutAttribute,

_ relation : NSLayoutRelation,

_ item2 : UIView? = nil,

_ attribute2 : NSLayoutAttribute = .NotAnAttribute,

constant : CGFloat = 0.0,

multiplier : CGFloat = 1.0) {

self.init(...)

}

}

Et voilà, we can now define Auto Layout constraints like this:

NSLayoutConstraint(view1, .Width, .Equal, view2, .Width)

NSLayoutConstraint(view1, .Width, .Equal, constant: 50)

NSLayoutConstraint(view1, .Width, .Equal, view1, .Height)

NSLayoutConstraint(view1, .Top, .GreaterThanOrEqual, view2, .Top)

I’ve simplified the exact thing I’ve done a bit for clarity, but I’ll have exactly the code I’m using in the end of this post. But before then, there are more ugly methods to fix!

UIView animation API

I have a general rule for designing methods: if you need autocompletion to use it, it should probably be simplified. This is not only for ease of reading and writing the code, but it's just a good idea to know method signatures by heart, and not having to rely so much on your IDE. People used to writing Objective-C will probably think this is impossible, since most of the APIs will need a notorious amount of typing. But it is, especially when using all the new features in Swift that reduces the amount of typing you will need. If you want to say more than you can express using a very few words in the method name, you put it in the documentation. I might actually I such a case use a not-very-descriptive word in the method, to invite eventual readers to alt-click the method, and read the documentation for it. Remember that people don't have to re-learn the method each time they see it.

The next API I will look at is the UIView animation API. This is how it looks in the (Swift version of the) UIView header file:

class func animateWithDuration(duration: NSTimeInterval, animations: () -> Void)

class func animateWithDuration(duration: NSTimeInterval, animations: () -> Void, completion: ((Bool) -> Void)?)

class func animateWithDuration(duration: NSTimeInterval, delay: NSTimeInterval, options: UIViewAnimationOptions, animations: () -> Void, completion: ((Bool) -> Void)?)

class func animateWithDuration(duration: NSTimeInterval, delay: NSTimeInterval, usingSpringWithDamping dampingRatio: CGFloat, initialSpringVelocity velocity: CGFloat, options: UIViewAnimationOptions, animations: () -> Void, completion: ((Bool) -> Void)?)

Since Objective-C doesn't have default values for parameters, this API defines multiple versions of the same method, each with a semi-random subset of the total parameters. It also translates the method name to a not very Swift-like ’animateWithDuration’, instead of just calling the method ’animate’, and having the first parameter name be ’duration’. These are just small annoyances, but it crosses the line when you want to make spring animations, where you will need the quite clumsy ’usingSpringWithDamping’ and ’initialSpringVelocity’ parameters, which has been added with another version of the same method, adding even more parameters. This means that if you have a piece of code like this:

UIView.animateWithDuration(0.3) { self.alpha = 0 }

And want to add a spring effect to the animation (disregarding that spring-animating alpha values doesn't look very nice), you would need to add 5 additional parameters, and move the animation block inside the method:

UIView.animateWithDuration(0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: nil, animations: { self.alpha = 0 }, completion: nil)

By just wanting to specify one more parameter, the simple readable method call turned into kind of a mess. You're probably going to be tweaking this animation a lot, so it should be fast and easy to change, add and remove options to this method. This is definitely a case of a method that could benefit from being Swift-optimized.

Extension UIView {

class func animate(duration : NSTimeInterval = 0.3,

delay : NSTimeInterval = 0,

springDamping : CGFloat? = nil,

springVelocity : CGFloat? = nil,

options : UIViewAnimationOptions = nil,

animations : Void -> Void,

completion : (Void -> Void)? = nil) {

// Call UIView animation methods here

}

}

I’ve made a few changes to the method signature here: First, I’ve put in some default parameters for everything. I’ve set the default duration to 0.3, which I think is a sensible default (These things also depend on wether you’re making this as a library for many people, or just for your own convenience. When just making them for yourself, you can have defaults that fit your needs). Then I’ve moved the duration name inside the parenthesis, and given some shorter names to the spring parameters. And then, of course, we only have one method, not four. Let’s make some animations:

UIView.animate { self.alpha = 0 }

UIView.animate(springDamping: 0.8) { self.alpha = 0 }

UIView.animate(duration: 2, options: .CurveEaseOut) { self.alpha = 0 }

It’s now much easier to change the options to the method, without having to rewrite it all. There’s also fewer things to type, fewer redundant "0" or "nil" arguments, and, I think most importantly, much easier to work with without relying on code completion, since you only have to write what you need. You might prefer it with a non-default value on the duration, but I like being able to just say “animate this”, and only give more exact instructions if the result isn’t as I wanted it.

(The only issue right now with the method is the completion block: if you want a completion on the method, you have to move the animation block inside the parenthesis. Unfortunately, I don’t have an easy fix for this. But this is also related to a whole other topic, that I might write about later, which is why callback blocks for async code is a bad idea.)

CGAffineTransform API

Next, I’m going to take a look at some of the C APIs still found around in UIKit and Foundation. Even in Objective-C, it was common to create object-wrappers for these, if you didn’t want to deal with them. So what’s so bad about them? Well, let’s try to define a transformation that translates, rotates and scales using CGAffineTransform:

var transform = CGAffineTransformMakeTranslation(100, 100)

transform = CGAffineTransformRotate(transform, CGFloat(M_PI_4))

transform = CGAffineTransformScale(transform, 0.5, 0.5)

This could be worse, but there’s still, first, a lot of typing the CGAffineTransform prefix, and second, there’s some places where it’s pretty clear that it wasn’t made for the language it’s being used in (such as having to cast M_PI_4 from Double to CGFloat)

There’s a few tricks in Swift we can use to fix these problems. Let’s take a look at what I’ve done to CGAffineTransform:

extension CGAffineTransform {

static var identity : CGAffineTransform { return CGAffineTransformIdentity }

init() {

self = CGAffineTransform.identity

}

func translate(x : CGFloat, y : CGFloat) -> CGAffineTransform {

return CGAffineTransformTranslate(self, x, y)

}

func rotate(angle : Double) -> CGAffineTransform {

return CGAffineTransformRotate(self, CGFloat(angle))

}

func rotate(angle : CGFloat) -> CGAffineTransform {

return CGAffineTransformRotate(self, angle)

}

func scale(scale : CGFloat) -> CGAffineTransform {

return CGAffineTransformScale(self, scale, scale)

}

func scale(x : CGFloat, y : CGFloat) -> CGAffineTransform {

return CGAffineTransformScale(self, x, y)

}

}

There’s a few things going on here. First of all, you might ask “But what, how are you able to make an extension to CGAffineTransform? Isn’t that just a C struct?” Well, yes it is, but extensions in Swift doesn’t work like categories in Objective-C. You’re able to extend all types in Swift, object type or not, and add functions to them. I say functions, because they’re not really methods; it’s essentially just syntactic sugar that makes it look like you’re calling methods on CGAffineTransform. What is actually happening is that it creates functions that take a CGAffineTransform as a parameter. But we don’t have to worry about that, all that matters is that yes, this is possible in Swift, and yes, it’s pretty awesome.

So what did we actually just add to CGAffineTransform? The first thing is pretty simple. It’s just a static variable to get an identity transform (static variables are only available to structs in Swift right now). you might say that that’s a weird thing to do, since CGAffineTransform.identity is not really much shorter than CGAffineTransformIdentity(), but if the compiler can infer that the current type is a CGAffineTransform, then you can just write “.identity” (as in let t : CGAffineTransform = .identity).

Next thing we’re doing is adding an initializer. This just returns an identity transform. Now we can create a transform with just ‘CGAffineTransform()’.

Now we have an easy way to get our initial transform, now we want to be able to actually modify it. We’ve added a transform function, which returns a new CGAffineTransform, that has been translated. We could have put a ‘mutable’ keyword in front of this function, and then actually changed the current transform, but it’s often a pretty good idea to create pure functions, instead of mutating state (the compiler will also often optimize away the copying).

Next, we create the rotate function. We wanted to solve the problem of not being able to pass in a Double, but we also still want to be able to pass in a CGFloat. Well, we can just create both functions, with the only difference in the signature being the type of the parameter, and Swift will automatically call the right one. This means that you can call .rotate() with both a CGFloat and a Double, and you can just add more types if you want. Neat!

Lastly is the scale function. In the C APIs, there’s just one scale function, which takes a horizontal and vertical scaling. It’s pretty common, though, to have these be the same value, to get a proportional scaling. That’s why I’ve defined two scale functions, one which take just a single value, and one which takes a value for each dimension. Even though the function name is the same, it will figure out wether you’re passing in one or two parameters, and call the correct function for you.

Let’s try to make our example from before with these new functions:

let transform = CGAffineTransform().translate(100, y: 100).rotate(M_PI_4).scale(0.5)

No writing CGAffineTransform everywhere, no mutable state, no casting. Short and sweet.

Custom initializers

Let’s try to make a UIButton. It will typically need a title, some coloring, a background image, maybe some rounded corners and a custom font.

let button = UIButton(frame: CGRectZero)

button.setTitle("I am Button", forState: .Normal)

button.setTitleColor(.blueColor(), forState: .Normal)

button.setBackgroundImage(UIImage(named: "button"), forState: .Normal)

button.clipsToBounds = true

button.layer.cornerRadius = 10

button.titleLabel?.font = UIFont(name: "Font", size: 20)

Hmm, kind of cluttered. And this view probably need a couple of buttons and labels. If your view class spends (And I use the word ‘spend’ very deliberately, since lines of code in one file shouldn’t be seen as an infinite resource) a lot of lines on cluttered setup like this, it’s probably time for some refactoring (And if this is in your view controller, then, wow). This is why I have custom convenience initializers for most common UIKit classes. Let’s take a look at them.

extension UIButton {

init(title : String? = nil, backColor : UIColor? = nil, titleColor : UIColor? = nil, fontSize : CGFloat? = nil, rounded : Bool? = nil, backImage : UIImage? = nil) {

// Set button properties accordingly

}

}

This might seem a little crazy. Six parameters? That quite a lot. The idea here is that you probably don’t need all of them at once, but you will probably need them all at different places. All the parameters have a default value of nil, and it will only be used if it is actually set to something. This means that we can create a button with a title like this:

let button = UIButton(title: "I am Button")

Or we can specify a lot of parameters:

let button = UIButton(title: "I am Button", titleColor: .blueColor(), fontSize: 20, rounded: true, backImage: UIImage(named: "button"))

The really nice thing about this is that before, we would need something like this to create the button:

class SomeView : UIView {

let button1 : UIButton

let button2 : UIButton

init(frame: CGRect) {

button1 = UIButton()

// set a lot of button1 properties

button2 = UIButton()

// set a lot of button2 properties

super.init(frame: frame)

}

}

Or like this:

class SomeView : UIView {

lazy var button1 : UIButton = self.setupButton1()

lazy var button2 : UIButton = self.setupButton2()

func setupButton1() -> UIButton {

let button1 = UIButton()

// set a lot of button1 properties

return button1

}

func setupButton2() -> UIButton {

let button2 = UIButton()

// set a lot of button2 properties

return button2

}

}

But with the new initializers, we can create the buttons inline, where we define them:

class SomeView : UIView {

let button1 = UIButton(title: "I am Button")

let button2 = UIButton(title: "Me too!", rounded: true)

So, we’ve now seen some examples of using the new features in Swift to make code a bit more concise and readable. Now, some people, maybe those still clinging on to Objective-C, will say, why does all this matter? Is it really so important to save a few characters?

And, well, yes, I think it’s pretty important. There are two big tasks you have when writing code: communicating instructions correctly to the computer, but also communicating intensions correctly to your fellow programmers (one of which might be your future self.) I think a large amount of problems in code, both quick mistakes and deeper, more complicated problems, are made when people don’t really have an overview of what the code actually does, and cannot quickly get it by quickly skimming through the source files.

This post has been about making code readable at the micro-scale, by optimizing each method. Another topic is organizing code at a larger scale, making your entire project welcoming and manageable. I will get into this topic in a future post, and yes, there will be some massive view controllers to get on a diet.

Appendix: What I’m using

I have two extensions on UIView:

func constraints(vertical : String? = nil, horizontal : String? = nil, _ views : [String : UIView]) -> [NSLayoutConstraint] {

var constraints : [NSLayoutConstraint] = []

if let v = vertical {

constraints += NSLayoutConstraint.constraintsWithVisualFormat("V:\(v)", options: nil, metrics: nil, views: views as NSDictionary) as [NSLayoutConstraint]

}

if let h = horizontal {

constraints += NSLayoutConstraint.constraintsWithVisualFormat("H:\(h)", options: nil, metrics: nil, views: views as NSDictionary) as [NSLayoutConstraint]

}

addConstraints(constraints)

for (_, view) in views {

view.setTranslatesAutoresizingMaskIntoConstraints(false)

}

return constraints

}


func constraint(item : UIView, _ attribute : NSLayoutAttribute, _ relation : NSLayoutRelation, _ item2 : UIView? = nil, _ attribute2 : NSLayoutAttribute = .NotAnAttribute, multiplier : CGFloat = 1, constant : CGFloat = 0, priority : UILayoutPriority = 1000) -> NSLayoutConstraint {

if item != self { item.setTranslatesAutoresizingMaskIntoConstraints(false) }

if item2 != self { item2?.setTranslatesAutoresizingMaskIntoConstraints(false) }

let constraint = NSLayoutConstraint(item: item, attribute: attribute, relatedBy: relation, toItem: item2, attribute: attribute2, multiplier: multiplier, constant: constant)

constraint.priority = priority

addConstraint(constraint)

return constraint

}

There are a few changes from the examples I used in the post. First, I don’t have a convenience initializer on NSLayoutConstraint, but a method on UIView, which has (almost) the same signature. This will automatically add the constraint to the view, and then return it, in case I need to refer to it later. Then I also call setTranslatesAutoresizingMaskIntoConstraints(false), because that thing is so damn annoying. This way, I’ll opt into it, rather than opt out of it. You might not want this if you still use autoresizing masks a lot. Also, you sometimes just need this to be true, if something in UIKit doesn’t use Auto Layout. Then I also have a parameter for priority.

I also have a convenience method for creating constraints with the visual ASCII-art format. This follows the same method of defining it as a method on UIView, rather than an initializer. I use the two methods something like this:

class SomeView : UIView {

func setupConstraints() {

let views = ["v": someSubview]

constraints(vertical: "|-20-[v]-20-|", views)

constraint(someSubview, .Width, .Equal, self, .Width, priority: 750)

}

}

The rest of the code matches pretty well what I’m using myself, except I have a few more. I have made my own custom initializer for most of the common UIKit classes, but it just follows the same style as the UIButton example. Then I also have some miscellaneous things, like a JSON and regex extensions on String. Now, go make your own!