Initializer in Swift

Today I want to give you an introduction in initialization 🏗

Joshua Brunhuber
joshtastic-blog
4 min readOct 14, 2018

--

Photo by Saad Salim on Unsplash

First things first: What is an initializer?

Initializer are simple methods which make your instance ready for usage. Imagine a truck which needs fuel. It would be a good design decision to make it mandatory to pass it as a parameter. But you don’t have to write them explicitly. Even if you haven’t declared any initializer, they’re still there. So this example

Class without explicit initializer.

is the same as:

Class with overridden empty initializer.

The same applies to deinit. It’s nearly the same as init but while init allocates memory for stored properties, deinit frees them up and make the memory available for other stuff.

Time for nerd stuff

Let’s check what the compiler is doing here. I created a Cat.swift example on my Desktop. Now call swiftc -emit-silgen Cat.swift and you’ll get the Bytecode (SIL) output. Implement the empty initializer from example2 and you’ll notice that nothing changed. If you take a closer look on the SIL output, you see that init and deinit are already included.

You can also use this command to write the text into a file:

Designated Initializer

Initializer for value types are pretty simple because they don’t support subclassing. The fun begins with initializer in classes. They offer us many possibilities. Let’s start with designated initializer. They are the main initializer. Let’s extend our cat 🐈 example.

The designated initializer initializes all stored properties. It get’s more interesting with inheritance:

What you see it that our designated initializer in Cat have to call the initializer from Animal because the name property have to initialized too. And this one is an important rule to remember: (from the Swift docs) Designated initializers must always delegate up.

Convenience Initializer

Now it’s time to instantiate a cat:

Woah. That are many parameters. And I think that every cat likes Pizza and Bates Motel. So let’s make the initialization a bit more convenient.

A convenience initializer musst call a designated initializer from the same class. They can’t call initializer from super-classes.

Required Initializer

Beside convenient initializer we also have required initializer. They force sub-classes to implement the initializer.

I’m going to change the designated initializer from Animal to a required initializer. What now happens is that the compiler forces us to implement the initializer in Cat. This ensures that all sub-classes from Animal can be instantiated with with a certain initializer.

Example

I see a big problem here. We haven’t enough animals. So we have to create a farm. And in order to do that, we need an animal factory. A method which takes the animals type and creates one for us. That means we have to instantiate instances during runtime by its type and therefore all initializer of all subclasses from animal have to conform to the same signature.

Let’s do this by declaring the init of Animal as required:

As mentioned above, we have to implement the required initializer in our Cat class.

Initializer Inheritance

Required initializer can be inherit from its super-class if no other initializer are implemented.

However when I create a custom initializer I’m forced to implement the required one too.

Implement a factory

Now we make use of our required initializers and create an Animal-Factory.

Because we know that every animal can be instantiated by its name, we can write this factory and create instances from a given type.

Conclusion

A simple way to remember this is: (Swift Docs)

Designated initializers must always delegate up.

Convenience initializers must always delegate across.

Required initializer make sure that subclasses conform to the same initialization signature.

Play with the playground 👾: https://cl.ly/cde03584baeb

--

--

Joshua Brunhuber
joshtastic-blog

iOS Developer📱 Nature🌲🍂 I also like music 🎸 and photography 📷