Initialization in Swift

In object-oriented programming languages, we need to instantiate the classes to use their properties and functions. In Swift, initialization can be defined as preparing the instance of a class, structure, and Enums. It allows us to set up the initial value for each stored property. We can place the code which is required at the time of initialization.

We can perform initialization by defining initializers which can be defined as the special methods called to instantiate the particular type. In Swift, initializers don't return a value. We can also implement the deinitializers, which can be used to place any cleanup code before the instance is deallocated.

Initial Values for Stored Properties

Initializers in Swift become more important due to the aspect that we cannot have stored properties in intermediate states. We must set all the stored properties to the initial values within the initializer or assigning a default value at the time of declaration.

Initializers

As we have already discussed in this article, the initializers are used to create a new instance of a particular type. An initializer can be defined using the init keyword as shown below.

Let's consider the following example, which defines a class Employee with a property name and initializer, which is used to initialize the name.

We can provide a default value to the class properties at the time of declaration. In the above example, instead of writing an initializer, we could have initialized the name property at the time of declaration, as shown below.

We can also customize the initialization by providing the initialization parameters at the time of object creation. Initialization parameters are similar to function and method parameters in terms of capabilities.

Let's consider the following example, which creates a Student class. A student can have a name, id, and age. We are initializing the properties of a student at the time of student creation.

Output:

"name: John, id: 1, age: 18"

We can define parameters with parameter names to be used inside the initializer's body. There can also be an argument label that will be used when the initializer is to be called.

Here, we must notice that initializers don't have any specific name, unlike methods and functions; therefore, the parameter names and argument labels play an important role in identifying which initializer is being called. However, argument labels are required to call an initializer.

Let's consider the following example.

Output:

"URL: https://www.javatpoint.com/, param: [\"name\": \"John\"], method: POST"
"URL: https://www.google.com, param: [:], method: GET"

However, like method calls, Swift allows us to use underscore (_) if we don't want to provide any argument label explicitly. Let consider the example in which we are using underscore (_) as an argument label.

Optional Properties

It is possible that our class has a property that may or may not has a value, i.e., we cannot set its value during initialization. In this scenario, we need to define such properties as optional. Optional properties are initialized to nil by default. Consider the following example in which the class department may or may not have an employee associated with it. Such properties are set optional during initialization.

This will print the following output on the console.

"John"
"David"

Initializing Constant Properties

The value of the constant properties can't be changed once they get initialized. However, we can define a constant property with no value, but we have to set the value for that property using initialization in the class only. We can't change the value for that property later on in the app.

Consider the following example.

This will give the following error in console.

error: cannot assign to property: 'name' is a 'let' constant
dep.name = "CS"
~~~~^~~~


MyPlaygroundInit.playground:11:5: note: change 'let' to 'var' to make it mutable
    let name:String
    ^~~
    var

Default Initialization

We can use Default Initializers in swift to initialize any structure and class. Default initializers are used to provide default values for all of their properties. We can use default initializers when there is no initializer in the class. In other words, we can say that the default initializer creates the new instance with all of its properties set to their default values.

Consider the following example.

As all properties of the Department class are set to their default values, therefore, it gets the automatic implementation of a default initializer that creates the new instance of the Department with their default values. In the example, the name property is set to nil by default as it is an optional property.

Memberwise Initializers for Structure Types

If we have observed structure types, we notice that the structure types have a memberwise initializer if they don't have any custom initializer. The structure type provides a default initializer where it doesn't default values of its properties.

Consider the following example, in which we have a structure named Color, which has three members Red, Green, and Blue. We can provide their values while instantiating the Color Structure.

When the structure properties have the default values, we may or may not pass the value for the already initialized value in the membership initializer, as shown in the following example.

In the above example, we could have also passed the value for the red color to overwrite its default value.

Initializer Delegation for Value Types

We can call the initializers from another initializer for reusing them to initialize the values. This process is known as initializer delegation to avoid duplicate code for initializing values.

Initializer delegation works differently for both value types and instance types. The value type doesn't support Inheritance; therefore, the process for initializer delegation is straightforward for value type. In Value types, initializers can only delegate to another initializer that they provide themselves.

For value types, we can use self.init to refer to other initializers in the same value type. However, we must notice that self.init can only be called within an initializer itself. If we define a custom initializer for any value type, we can't access the default initializer for that type.

Let's consider the following example, in which there's a Structure called Item, which refers to two supporting structures as Color to define an Item's color and its size.

However, we can define the three initializers for Item structure in the following three ways, either by using the default values for the Item properties or by setting the specific properties.

The first Item initializer, init() works like a default initializer for the structure, assigning the default values for Item properties. If we use init(){ } to assign the default values for the Item structure as shown below.

The second initializer, init(name:color:size), is similar to the memberwise initializer that the structure has when it doesn't have its custom initializer.

The Third initializer, init(name:red:size), is a bit complex than the previous ones. It receives a red color used to decide the other color factor, i.e., green and blue. Once we calculate the color, we can call init(name:red:size) from the initializer.

Initialization in Reference Types

We need to ensure that all of the stored properties of a class, including the properties it inherits, are assigned an initial value during initialization.

For this purpose, Swift provides two types of Initializers which help class types to ensure that all properties are assigned to an initial value.

The types of class Initializers are given as follows.

Designated Initializers

A designated Initializer is used as the primary initializer for a class. The designated initializer initializes all of the properties of a class and calls the appropriate superclass initializer to continue with the initialization. Designated Initializer is seen as a starting point through which the initialization process gets started. The classes generally don't have multiple initializers. However, every class must have at least one designated initializer. The syntax for declaring Designated Initializer is given below.

Convenience Initializers

Convenience Initializers are secondary initializers for a class and work as supporting initializers to Designated Initializers. We can have Convenience Initializer in a class that calls a designated initializer from the same class. We can also use the Convenience Initializer to instantiate a class for some specific use case or input type.

However, we don't need to use convenience initializers in the class if it doesn't require one. The syntax to declare the convenience initializer is given as follows.

Initializer Delegation in Class

Swift provides the following three simple rules to define the relationship between Designated and Convenience Initializers.

  1. A designated initializer must call another designated initializer defined in its immediate superclass.
  2. A convenience initializer must call another initializer defined in the same class.
  3. A convenience initializer must call a designated initializer either through a chain of convenience initializers or directly.

In other words, we can say that the convenience initializer always delegates across the class level, whereas the designated initializer delegates up the class level.

Let's consider the following example, which uses the Convenient and Designated Initializers to initialize the stored properties in a class.

In the above example, class Person has one designated initializer and one convenience initializer. The class Person can be instantiated using a specific argument called name, as shown below.

Here, the designated initializer from the Person class ensures that all the stored properties are fully initialized. However, the Person class also provides a convenience initializer to instantiate the Person class by not providing a name. The init() initializer calls the designated init with a default name ("Unnamed") and assigns the Person name with a value.

Now, let's define another class in the hierarchy, which is the Employee class. It adds two more properties to the hierarchy, i.e., salary and id. It also defines two initializers to initialize the stored properties.

The Employee class has one designated initializer, which can be used to set all the properties of a new instance. In the designated initializer, the salary and id are initialized first, and then the designated init of the superclass is called. This is called Two-Phase Initialization, which will be discussed in this article.

However, The Employee class also contains a convenience initializer that can instantiate the Employee class using name only. It provides default values for the salary and id of the Employee. It's more convenient to create an Employee class using a convenient initializer because we don't need to provide the values for salary and Id at the time of object creation.

Here, we must also notice that the Convenience Initializer used in the Employee class takes the same parameter name as the Designated Initializer from the Person class. This convenience initializer overrides a designated initializer from its superclass.

The Employee class can be instantiated using the following three ways.






Latest Courses