Swift Initializer

An initializer is a special type of function that is used to create an object of a class or struct.

In Swift, we use the init() method to create an initializer. For example,

class Wall {
  ...

  // create an initializer 
  init() {
    // perform initialization
    ... 
  }
} 

Here, the method init() is an initializer of the class Wall.


Example: Swift Initializer

// declare a class
class  Wall {
  var length: Double

  // initializer to initialize property
  init() {
    length = 5.5
    print("Creating a wall.")
    print("Length = ", length)
  }
}

// create an object
var wall1 = Wall()

Output

Creating a wall.
Length =  5.5

In the above example, we have created an initializer named init(). Inside the initializer, we have initialized the value of the length property.

Notice the following statement:

// create an object
var wall1 = Wall()

Here, when the wall1 object is created, the init() initializer is called. And, the value of the length property is initialized to 5.5.


Parameterized Initializer

A Swift initializer can also accept one or more parameters. Such initializers are known as parameterized initializers (initializers with parameters).

Let's see an example,

class Wall {
  
  var length: Double
  ...
  
  // initializer with parameter
  init(length: Double) {

    self.length = length
  } 
}

// create an object
var wall1 = Wall(length: 10.5)

Here,

  • init(length: Double) - initializer with parameter length
  • var wall1 = Wall(length: 10.5) - pass value 10.5 to the parameter length
  • self.length = length - assigns the value of the length parameter (10.5) to the length property
  • self.length - specify that the length property is associated with the current object which is wall1

Example: Parameterized Initializer

// declare a class
class Wall {
  var length: Double
  var height: Double

  // parameterized initializer to initialize properties
  init(length: Double, height: Double) {
    self.length = length
    self.height = height
  }

  func calculateArea() -> Double {
    return length * height
  }
}

// create object and initialize data members
var wall1 = Wall(length: 10.5, height: 8.6)
var wall2 = Wall(length: 8.5, height: 6.3)

print("Area of Wall 1: ", wall1.calculateArea())
print("Area of Wall 2: ", wall2.calculateArea())

Output

Area of Wall 1:  90.3
Area of Wall 2:  53.55

In the above example, we have created an initializer init() with two parameters: length and height. Notice the expressions,

var wall1 = Wall(length: 10.5, height: 8.6)
var wall2 = Wall(length: 8.5, height: 6.3)

Here, while creating an object of the Wall class, we pass the values for the member properties as arguments.

With the member variables thus initialized, we can now calculate the area of the wall with the calculateArea() method.


Initializer Overloading

Swift Initializers can be overloaded in a similar way as function overloading.

In initializer overloading, two or more initializers can have the same name if they have different types or numbers of parameters.

And, based on the arguments passed during the object creation, the corresponding initializer is called.

Let's see an example,

class Person {
  var age: Int

  // 1. initializer with no arguments
  init() {
    age = 20
  }

  // 2. initializer with an argument
  init(age: Int) {
    self.age = age
  }

  // method to return age
  func getAge() -> Int {
    return age
  }
}

var person1 = Person()
var person2 = Person(age: 23)

print("Person1 Age:", person1.getAge())
print("Person1 Age:", person2.getAge())

Output

Person1 Age: 20
Person1 Age: 23

In the above example, we have created a class Person that has a single property age.

We have also defined two initializers: init() and init(age: Int).

  1. We have not passed any argument to the person1 object, so the first initializer is called. Hence, age is initialized to 20.
  2. We have passed 23 as an argument to person2. So, the second initializer is called and age is initialized to 23.

The method getAge() returns the value of age, and we use it to print the age of person1 and person2.


Swift convenience Initializer

In previous examples, the initializer we defined were primary initializers of the class. These primary initializers are also called designated initializers.

However, we can also define a secondary/supporting initializer for a class called convenience initializer.

To define a convenience initializer, we use the convenience keyword before the initializer. For example,

class University {
  
  var name : String
  var rank : String
  
  init(name : String, rank: String) {
    self.name = name
    self.rank = rank
  }

  // define convenience init  
  convenience init() {
    self.init(name: "Kathmandu University", rank: "1st")
  }
  
}

var university1 = University()
print(university1.name)
print("Rank:", university1.rank)

Output

Kathmandu University
Rank: 1st

In the above example, we have created a designated initializer: init() and a convenience initializer: convenience init().

Inside the convenience initializer, we have called the designated initializer and assigned values to the properties.

convenience init() {
  self.init(name: "Kathmandu University", rank: "1st")
}

When the university1 object is created, the convenience initializer is called.

// using convenience initializer
var university1 = University() 

This makes our code look cleaner compared to calling the designated initializer:

// call designated initializer
var university1 = University(name: "Kathmandu University", rank: "1st") 

Note: Convenience Initializers are useful when it comes to assigning default values to stored properties.


Failable Initializer

In some cases initializers might or might not work, this is called a failable initializer.

We write a failable initializer by placing a question mark (?) after the init keyword and return nil if something goes wrong. For example,

class File {

  var folder: String

  // failable initializer
  init?(folder: String) {

    // check if empty
    if folder.isEmpty {
      print("Folder Not Found") // 1st output
      return nil
    }
    self.folder = folder
  }
}

// create folder1 object
var file  = File(folder: "")
if (file != nil) {
  print("File Found Successfully")
}
else {
  print("Error Finding File") // 2nd output
}

Output

Folder Not Found
Error Finding File

In the above example, we have created the failable initializer init?() with a parameter named folder.

And, we have used the if statement and the isEmpty property

if (folder.isEmpty) { return nil }

to check if the folder is empty and returns nil if it is empty.

For the folder1 object, we have passed an empty string "" which triggers an initialization failure, so the statement inside it is executed first and then it returns nil.

And finally, the statement inside the else block is executed


Memberwise Initializer for structs

In Swift, we are not required to create an initializer while working with structs. Swift automatically generates a memberwise for us. For example,

struct Person {
  
  var name: String
  var age: Int
}

Here, we have not created any initializer inside the Person struct. However, Swift auto generates a memberwise initializer for us,

var person1 = Person(name: "Dwight", age: 43)

Here, values inside the parentheses () are automatically assigned to corresponding properties of the struct. This is called a memberwise initializer.


Example: Memberwise Initializer

struct Person {

  // define two properties  
  var name: String
  var age: Int
}

// object of Person with memberwise initializer  
var person1 = Person(name: "Dwight", age: 43)

print("Name:", person1.name)
print("Age:", person1.age)

Output

Name: Dwight
Age: 43

In the above example, we have used the auto-generated memberwise initializer to assign values to corresponding properties of the Person struct.

var person1 = Person(name: "Dwight", age: 43)

Here, the value of name is set to Dwight, and age is set to 43.

Did you find this article helpful?