Swift Initialization and the Pain of Optionals

Swift’s strict initialisation process results in a number of practical issues, leaving developers scratching their heads. This post explores a few solutions including two-phase initialisation, the use of optionals and lazy properties.

Introduction

Swift is an opinionated language. It is clear that it was designed with strictness and safety in mind.

One of the more radical features of this language is that it doesn’t permit nil references.

Unlike most other mainstream languages you have to explicitly opt-in to nil via the use of optionals. Whilst this sounds like a very sensible concept it has a knock-on effect to the seemingly simple task of initialising objects.

You’ll find questions cropping up all over
StackOverflow, Reddit and Twitter where developers are baffled by the simplest task of how to initialise the properties of a class.

Let’s take a look at this problem …

Strictness bites

When you first start programming in Swift you will no doubt discover that it is very fussy about where you initialise the properties of a class. Here’s a quick example:

One of Swift’s rules is that you must initialise all the properties of a class before initialising the superclass. This avoids issues that can arise if a super initialiser calls a method which is overridden resulting in inconsistent state. For a simple illustration of the issue, take a look at this gist.

OK … so let’s shift it before the super.init call:

classViewController:UIViewController{privateletanimator:UIDynamicAnimatorrequiredinit(coderaDecoder:NSCoder){// use of property 'view' in base object before super.init initializes itanimator=UIDynamicAnimator(referenceView:self.view)super.init(coder:aDecoder)}}

Unfortunately you cannot use the view property of the superclass before there super initializer has been invoked.

So, what next? How about taking a two-phase approach; first initialising the UIDynamicAnimator, then setting the reference view after the superclass has been initialised?

classViewController:UIViewController{privateletanimator:UIDynamicAnimatorrequiredinit(coderaDecoder:NSCoder){animator=UIDynamicAnimator()super.init(coder:aDecoder)// ERROR: Cannot assign to the result of this expressionanimator.referenceView=self.view}}

Unfortunately the referenceView property is read only, so that isn’t going to help much. Furthermore, accessing the view property of a view controller within the initialiser is unsafe, it results in an NSInternalInconsistencyException being thrown as it attempts to load the view.

NOTE: There is nothing inherently wrong with the code above, and in some cases a two-phase approach of initialisation and configuration will work just fine. Just not in this case … and numerous others!

Options, options, optionals

When faced with this problem, (as most Swift developers are, on a daily basis!) there are a number of different techniques that can be used to circumnavigate this restriction.

Let’s take a look at some of them.

Make the property a variable

If you’re new to Swift, your first thought might be to change the property from being a constant (let), to a variable (var):

privatevaranimator:UIDynamicAnimator

Recall that table at the start of this post? That’s right, Swift doesn’t support nillable references. All properties, regardless of whether they are constants or variables, must be initialised.

Make the property an optional variable

Swift doesn’t allow nil references, but similar behaviour is possible via optionals. One practical solution to this problem it to change the property type to an optional UIDynamicAnimator?:

The subtle difference here is that you can now pretend that this property isn’t an optional, and invoke methods directly:

animator.addBehavior(UIGravityBehavior())

But let’s face it, this isn’t much better that the earlier solution.

I am firmly of the opinion that no language designer in their right minds would dream up the concept of implicitly unwrapped optionals! Their sole reason for existence is the need to interop with Objective-C, a language which permits nil references and as a result where almost anything could be nil.

I see implicitly unwrapped optionals as a legacy-support concept and avoid them where possible.

Lazy stored properties

Lazy properties are an interesting language feature, where a property value is initialised the first time it is accessed. You can make a property lazy by simply adding the lazy keyword:

lazyprivatevaranimator=UIDynamicAnimator()

Notice that the lazy property uses the var keyword, hence it is a variable and can be re-assigned.

Unfortunately you cannot pass values to the initialiser, as a result the following will not compile:

lazyprivatevaranimator=UIDynamicAnimator(referenceView:self.view)

However, you can use a closure expression to initialise the lazy property:

When the animator property is first accessed, the closure is invoked, which results in the construction of the UIDynamicAnimator. The closure in this example is a simple one-liner, but more complex initialisation is entirely possible.

In my opinion this solution is an improvement on those that require the use of optionals, and one which I have used myself on a number of occasions. However it is far from perfect:

Firstly, the animator property is still a variable, when conceptually it is a constant.

Secondly, lazy properties are initialised when they are first accessed. If the initialisation logic has side-effects (for example it changes the view), you have to be careful about where and when this initialisation takes place.

Conclusions

Whilst Swift’s two-phase initialisation was designed with safety in mind, it has resulted in some tricky problems for developers, often forcing us into a slightly uncomfortable usage of optionals.

I do feel that lazy properties provide a slightly more palatable solution, although they are far from perfect.

I am sure there are other techniques that can be employed to overcome this issue. If you have any ideas, please share them in the comments below.

Read more

I am Technology Director at Scott Logic and am a prolific technical author, blogger and speaker on a range of technologies.

My blog includes posts on a wide range of topics, including HTML5 / JavaScript and data visualisation with D3 and d3fc. You'll also find a whole host of posts about previous technology interests including iOS, Swift, WPF and Silverlight.