“I also like beets. (But not with cheese.)” – The Swift Programming Language

If you’ve been coding in Swift for over an hour and a half, you’ve probably come across more than a few of these unforgettables:

Property ‘self.propertyInDerivedClass’ not initialized at super.init call
Use of ‘self’ in property access ‘propertyInBasClass’ before super.init initializes self
A non-failable initializer cannot chain to failable initializer ‘init(coder:)’ written with ‘init?’

Placating the compiler has gotten trickier with each update, causing a bit of consternation in the community. But I think a lot of the trouble simply comes down to the jargon. Default, memberwise, designated, convenience, failable, nonfailable–it’s a regular menagerie out there. So, I thought I’d run through some quick definitions, and throw in a a few gotchas along the way. This will be a cursory look, but enough to decode most of the compiler errors you’ll run into. There’s no substitute for the documentation (and the blog post about the documentation).

Default and Memberwise Initializers

Mercifully, these two are just what they sound like–and even better, we get them for free. Whenever a class provides default property values along with each property’s declaration, Swift synthesizes a default initializer “behind the scenes.” Take a simple class, with all properties initialized:

class DVComplex {
    var real: Float = 0
    var imag: Float = 0
}

The line var point = DVComplex() calls the default initializer, and we get back a variable with properties initialized to their defaults. The behavior here would be equivalent to if we had declared it like this:

class DVComplex {
    var real: Float = 0
    var imag: Float = 0
    init() {} // Default initializer
}

If we had declared our object as a struct instead of a class, we would additionally get a memberwise initializer. As soon as we begin typing var point = DVComplex(, Xcode catches on and gives us a couple of options:

Swift Initialization Error

The first is the default initializer, which behaves the same as before. The second is the memberwise initializer, which lets you define your own values. The behavior we’re seeing is identical to if we’d typed this:

struct DVComplex {

    var real: Float = 0
    var imag: Float = 0

    init(){} // Default

    init(real: Float, imag: Float) { // Memberwise
        self.real = real
        self.imag = imag
    }
}

One subtlety deserves to be articulated: the synthesized memberwise initializer includes all properties, including those marked private. So if you, like me, mark properties as private with the expectation that they will be invisible to the user of the class, then you’ll need to write your own initializer, which stops Swift from making either default or memberwise initializers for you.

Designated and Convenience Initializers

Wouldn’t it be convenient if we could initialize either in cartesian coordinates, or in polar coordinates? Sure would. Now, there are a few ways we could go about this. The first would be to define a brand new initializer, just as before.

class DVComplex {
    
    // ...
    
    init(magnitude: Float, phase: Float) {
        self.real = magnitude * cos(phase)
        self.imag = magnitude * sin(phase)
    }
    
}

In this case, both our initializers are what we would call designated initializers, because they initialize all properties declared in the class. However, we could just as well have defined it as a convenience initializer. A convenience initializer must always call a designated initializer from the same class. And–pro tip–you can define convenience initializers in extensions, which can help you organize your own code, but also means that you can provide them for classes you didn’t write.

extension DVComplex {
    
    convenience init(magnitude: Float, phase: Float) {
        let real = magnitude * cos(phase)
        let imag = magnitude * sin(phase)
        self.init(real: real, imag: imag)
    }
    
}

But the volume doesn’t really get turned up until we start talking about inheritance. Let’s define a subclass and start playing around.

class DVUnnecessarilyComplex: DVComplex {
    var unreal: Float = 0
    var magical: Float = 0
}

Since we provide values for all properties, and don’t provide any new initializers, our subclass can fall back on the initializer(s) for the superclass. But let’s say we hadn’t provided values, and wanted to let the user initialize all four properties. We could try it a few different ways before getting it right.

    init(real: Float, imag: Float, unreal: Float, magical: Float) {
        self.real = real // Use of 'self' in property access 'real' before super.init initializes self
        self.imag = imag
        self.magical = magical
        self.unreal = unreal
    }
    init(real: Float, imag: Float, unreal: Float, magical: Float) {
        super.init(real: real, imag: imag) // Property `self.unreal` not initialized at super.init call
        self.magical = magical
        self.unreal = unreal
    }
// Success!
    init(real: Float, imag: Float, unreal: Float, magical: Float) {
        self.magical = magical
        self.unreal = unreal
        super.init(real: real, imag: imag)
    }

The key here is the concept of two-phase initialization. In a nutshell: a class assigns values to all properties that it defines, and then calls an initializer in the superclass. Phase 1 isn’t complete until all properties have assigned a value. Only then can an initializer reference properties defined in the superclass. Colin Eberhardt has a great discussion about this, with a few tricks for navigating particularly rocky channels–a quick read, and quite well-considered. And as an added bonus, by defining our own designated initializer, we’ve lost the initializers we defined for our superclass; and this is true even if we provide values during declaration. Sigh…can’t win them all…

…or can we? We can actually get back our convenience init by overriding the superclasses designated and default initializers:

    override init(){super.init()}
    override init(real: Float, imag: Float) {
        super.init(real: real, imag: imag)
    }

Initializer inheritance is itself quite a complicated topic in Swift–suffice it to say that the initializers are inherited in this case, and put it aside for another post. :-)

Failable/Nonfailable Initializers

All of the initializers we have written so far have been nonfailable. Try as you might, nothing you provide the initializer will cause initialization to fail at runtime. (Obviously, at compile time, failure is always an option: DVComplex(real: "Labrador", imag: "Dumbledore")). And sometimes failure is inevitable. In these cases, Swift gives us what is, IMHO, a very elegant solution. Let’s modify one of the initializers from DVComplex, to allow for it to fail in extreme and unforeseen circumstances.

    init?(real: Float, imag: Float) {
        self.real = real
        if abs(imag) >= 0 {
            self.imag = imag
        } else {
            print("Sorry, I don't have an imagination.")
            return nil
        }
    }

Depending on how closely you’ve been following along, you might notice that this causes an error to crop up in our convenience initializer:

extension DVComplex {
    
    convenience init(magnitude: Float, phase: Float) {
        let real = magnitude * cos(phase)
        let imag = magnitude * sin(phase)
        // A non-failable initializer cannot delegate to failable initializer
        // 'init(real:imag:)' written with 'init?'
        self.init(real: real, imag: imag)
    }
    
}

Makes sense. And the fix is easy, too: convenience init?(magnitude: Float, phase: Float) { /* ... */ }.

Lastly: Property Observers are Not Called When Set During Initialization

One final gotcha. Let’s say you have a numerical value with well-defined upper and lower bounds, and it is important to respect those bounds to prevent utter disaster and calamity. It might be reasonable to define a struct that enforced the limits, so that you don’t need to continually do the bounds checking in your code.

struct BoundedValue {
    
    let minimum: Float
    let maximum: Float
    var value: Float {
        didSet { self.value = min(max(value, self.minimum), self.maximum) }
    }
    
    init(min: Float, max: Float, val: Float) {
        self.minimum = min
        self.maximum = max
        self.value = val
    }
    
}

Most of the time, this works great. You initialize your variable to something sensible, but then recklessly set value to an out-of-bounds value. Luckily, the property observer saves the day:

var x = BoundedValue(min: 0.0, max: 1.0, val: 0.5)
x.value = 1.5 // Whoops!
x.value // 1

BUT, since the property observer isn’t called during initialization, there’s nothing to stop this bit of horribleness from happening:

x = BoundedValue(min: 0.0, max: 1.0, val: 1.5)
x.value // 1.5

Boo. Of course, it makes quite a lot of sense that property observers aren’t called during initialization–because whatever the property observer is doing might very well depend on values that aren’t yet set. In this case, minimum and maximum were set by the time we set value, but we could just as easily have done it the other way around, in which case didSet wouldn’t have had all the information it needed. In this case, though, there’s an easy fix:

struct BoundedValue {
    
    let minimum: Float
    let maximum: Float
    private var rawValue: Float
    var value: Float {
        get { return min(max(self.rawValue, self.minimum), self.maximum) }
        set { self.rawValue = newValue }
    }
    
    init(min: Float, max: Float, val: Float) {
        self.minimum = min
        self.maximum = max
        self.rawValue = val
    }
    
}

Phew! Dodged a bullet there. And so, my friends, we’ve reached the end. Or is it…just the beginning? Ten…nine…eight…

P.S. Thanks to @hanning_thomas for naming this one of the best iOS articles of the month!