Swift classes: beyond basics

Designated initializer: (no keyword required)

What is it: you already know about it and have used it. It actually is the normal initializer we have written in the previous lesson, it just happens to have a specific name which you now know. It is available in both the superclass and any of the subclasses.

Take it as a way of differentiating between all the class possible initializers.

Why use it: in order to give values to all the class properties. As you know, a class needs to ensure that all its properties have values. This happens during the initialisation process, which takes place when you create an instance of that particular class.


Where the new part starts is from here, with convenience, required and failable initializers:

Convenience initializer: keyword used is convenience (before init)

What is it: you have probably seen something similar in the structures post, where we used initializer delegation. This seems to be the same thing, but applied to classes.

Why use it: You use it to create different paths for initialising your class. However, with this type of initializers you will eventually have to reach out to the class designated initializer (through self.init()) to make sure that the class is ready to be used.

In this type of initializer you will have to assign default values to those properties not initialised through the convenience initializer parameters.

As you can see below, savingsTarget gets a default value, while the convenience parameter’s value for initialBalance will be assigned to the class’s property named initialBalance (we use self to distinguish between the class and the init parameters).

Conveniance initialiser

Required initializer: keyword uses is required (before init)

What is it: If you specify a superclass designated initializer to be required, all subclasses of that class will have to implement that initializer.

Superclass use of required initializer

When you implement this initializer in the subclass you do not have to use the keyword override (as you would normally use when overriding the superclass init), as you are not overriding the superclass this time. You have to use the keyword required instead.

This in effect will add a second designated initializer to your class, which is fine.

There is a difference between a normal initializer and a required initializer which I noticed while playing with those 2 concepts:

It seems that if you have subclass specific properties to initialise (which are not in the superclass), with a required initializer you will have to give them default values. If you use a designated initializer you will initialise the specific properties first, followed by calling the superclass initialiser to take of care its properties. See below where ownFeature was assigned a default value.

Use of required init in a subclass

Why use it: This guarantees that the subclass will have the superclass’s initializer. Apparently there might be situations where a subclass doesn’t have an initializer, and you need to make sure that it has one.

Failable initializer: sign used is ? after init, or ! for explicitly unwrapped -init?() / init!()

What is it: it is an initializer that returns an optional instance of the type. This is relevant if you think that your instance might fail when initialised.

How and when can your initialisation fail: It can fail when one of the values passed to the initializer’s parameter somehow fails / returns nil or its value doesn't exist. The result of the initialisation will be a nil in this case. This means that you will have to unwrap the instance before use.

Use of failable initializer

Why use it: Based on its failure you will execute different code. It is a good way to ensure that a certain condition is met before initializing the object.


Summary:

Designated initializer:

  • it is just the normal initializer used to assign values to the instance’s property

keyword: none

Convenience initializer:

  • it is a way to delegate initialization to a different initializer.
  • this type of initializer will eventually call the designated initializer to complete the initialization of the type

keyword: convenience init()

Required initializer:

  • it is use to mandate the use of the superclass initializer in all its subclasses
  • the required initializer in the subclass will use the same keyword

keyword: required init()

Failable initializer:

  • it is used when one of the properties of the class might fail.
  • the return will be an optional instance, which will need to be unwrapped

keyword: init? or init!

Like what you read? Give Cosmin Mircea a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.