Swift - Initialization



Initializers are used to create instances of class, structure or enumeration. It makes sure that all properties of the instance are set to suitable initial values before the use of the instance. If we do not create an initializer in the class, structure or enumeration, then Swift will automatically create an initializer for the instances.

They do not return any value; their main goal is to make sure that the new instance of any type is initialized correctly before it will be used for the first time. Swift also provides a de-initialization process for performing memory management operations once the instances are deallocated.

Defining Initializer in Swift

In Swift, the initializer is created by using the init keyword. It may or may not have parameters.

Syntax

Following is the syntax of the initializer −

init() {
   //New Instance initialisation goes here
}

Example

Here the structure 'rectangle' is initialized with members’ length and breadth as 'Double' datatypes. Init() method is used to initialize the values for the newly created members length and double. The area of a rectangle is calculated and returned by calling the rectangle function.

struct rectangle {
   var length: Double
   var breadth: Double

   // Initializer
   init() {
      length = 6
      breadth = 12
   }
}
var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

Output

It will produce the following output −

area of rectangle is 72.0

While creating an instance of any particular type always remember the stored properties must be initialised before the instance is created. They can’t be left in an indeterminate state. We can initialize stored properties either in the instance or by assigning a default value as part of their definition.

Setting Property Values by Default

We can initialize the stored property using the init() initializer or the user has a provision to initialize the property values by default while declaring the class or structure members. When the property takes the same value alone throughout the program we can declare it in the declaration section alone rather than initializing it in init().

Example

struct rectangle {

   // Properties with default value
   var length = 6
   var breadth = 12
}

// Instance of rectangle structure
var area = rectangle()
print("Area of rectangle is \(area.length*area.breadth)")

Output

It will produce the following output −

Area of rectangle is 72

Parameters Initialization

We are allowed to initialize the properties of the instance by passing parameters to the initializer. It is the part of the initializer's definition using init().

Example

// Structure
struct Rectangle {

   // Properties
   var length: Double
   var breadth: Double
   var area: Double
    
   // Initializer with parameters
   init(fromLength length: Double, fromBreadth breadth: Double) {
      self.length = length
      self.breadth = breadth
      area = length * breadth
   }
}

// Instance of structure 
let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("area is: \(ar.area)")

Output

It will produce the following output −

area is: 72.0

Local & External Parameters

Initialization parameters have both local and global parameter names similar to those of function and method parameters. Local parameter declaration is used to access within the initialize body and external parameter declaration is used to call the initializer.

Swift initializers differ from function and method initializers in that they do not identify which initializers are used to call which functions.

So to overcome this, Swift introduces an automatic external name for every parameter in init(). This automatic external name is equivalent to the local name written before every initialization parameter.

Example

struct Days {
   // Properties
   let sunday, monday, tuesday: Int
    
   // Initializer with parameter names
   init(sunday: Int, monday: Int, tuesday: Int) {
      self.sunday = sunday
      self.monday = monday
      self.tuesday = tuesday
   }
}

// Instance of structure
let week = Days(sunday: 1, monday: 2, tuesday: 3)
print("Days of a Week is: \(week.sunday)")
print("Days of a Week is: \(week.monday)")
print("Days of a Week is: \(week.tuesday)")

Output

It will produce the following output −

Days of a Week is: 1
Days of a Week is: 2
Days of a Week is: 3

Parameters without External Names

When an external name is not needed for an initialize underscore '_' is used to override the default behavior.

Example

struct Rectangle {
   var length: Double
    
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
    
   init(frombre bre: Double) {
      length = bre * 30
   }
    
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Output

It will produce the following output −

area is: 180.0
area is: 370.0
area is: 110.0

Optional Property Types

When the stored property at some instance does not return any value that property is declared with an 'optional' type indicating that 'no value' is returned for that particular type. The property that was declared as 'optional' will automatically initialize with nil value during initialization.

Example

struct Rectangle {

   // Optional property type
   var length: Double?
    
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
    
   init(frombre bre: Double) {
      length = bre * 30
   }
    
   init(_ area: Double) {
      length = area
   }
}

// Instances of structure
let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Output

It will produce the following output −

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

Assigning Constant Properties During Initialization

We are allowed to assign a value to a constant at the time of initialization and once the constant property is assigned a value we cannot modify that value further, if we try to do we will get an error. Also, a constant property of the class instance can be modified during the initialization by the class in which it is introduced not by the subclass.

Example

class Rectangle {

   // Constant property
   let length: Int  

   var breadth: Int

   // Initializer
   init(breadth: Int) {
      self.breadth = breadth
        
      // Assigning a value to the constant property during initialization
      self.length = 34  
   }
    
   // Method using constant property
   func area() -> Int {
      return length * breadth
   }
}

// Creating an instance 
let obj = Rectangle(breadth: 10)

// Accessing the constant property
print("The value of length is: \(obj.length)")

let ar = obj.area()
print("The area of the Rectangle is: \(ar)")

Output

It will produce the following output −

The value of length is: 34
The area of the Rectangle is: 340

Default Initializers

Default initializers are those initializers that are automatically created by the Swift compiler when a class or structure does not contain any customised initialiser or all the properties have default values. They are used to create instances of a class or structure with all its properties set to their default values.

Example

class defaultexample {

   // Properties with default value
   var stmark = 98
   var pass = true
}

// Creating an instance with default initializer
var result = defaultexample()

// Accessing properties
print("result is: \(result.stmark)")
print("result is: \(result.pass)")

Output

It will produce the following output −

result is: 98
result is: true

Memberwise Initializers for Structure Types

In Swift, if a structure type does not have its custom initializer, then it will automatically receive the 'memberwise initializer’. They also receive the 'memberwise initializer’ if they have stored properties that do not contain default values. The new instance properties are passed to the memberwise initialize by name.

Example

struct Rectangle {
   var length = 100.0, breadth = 200.0
}

// Instance with memberwise initializers 
let area = Rectangle(length: 24.0, breadth: 32.0)

print("Area of rectangle is: \(area.length)")
print("Area of rectangle is: \(area.breadth)")

Output

It will produce the following output −

Area of rectangle is: 24.0
Area of rectangle is: 32.0

Initializer Delegation

Initializer Delegation is defined as calling initializers from other initializers. Its main function is to act as reusability to avoid code duplication across multiple initializers.

Rules for Initializer Delegation

Following are some rules that an initializer delegation follows while working with values types and class types −

For Value Types (Structures and Enumerations)

  • Inheritance is not supported for value types. So the initializer delegation for value types calls another initializer within the same type.

  • It does not have any concept of subclass. Hence the designated initializers are the main initializers for complete initialization.

  • Value types use self.init to refer to other initializers of the same value type.

  • They automatically receive a member wise initializer for their properties.

For Class types

  • Inheritance is supported. Hence the classes have to make sure that all the stored properties they inherit must be assigned with a suitable value during initialization.

  • It has the concept of subclass. Hence the designated initializers in a class can call the designated initializers of its immediate super class using super.init.

Example

Swift program to demonstrate initializer delegation for value types.

struct Car {

   var price: Int
   var quantity: Int

   // Designated initializer
   init(price: Int, quantity: Int) {
      self.price = price
      self.quantity = quantity
   }

   // Convenience initializer delegating to the designated initializer
   init(monzaCar: Int) {
      self.init(price: monzaCar, quantity: monzaCar)
   }

   // Convenience initializer with default values
   init() {
      self.init(price: 2245622, quantity: 1)
   }
}

// Creating instances
let obj1 = Car(price: 2000000, quantity: 1)
let obj2 = Car(monzaCar: 34)
let obj3 = Car()

print(obj1)        
print(obj2)            
print(obj3)  

Output

It will produce the following output −

Car(price: 2000000, quantity: 1)
Car(price: 34, quantity: 34)
Car(price: 2245622, quantity: 1)

Class Inheritance and Initialization

As we all know a class has stored properties including the properties it inherits from the superclass. So all these properties must be initialised with an initial value at the time of initialization. So to initialize these properties Swift provides two types of initializers and they are −

Designated Initializer

It is the main initialiser for a class. It initializes all the properties of the class and can also initialize inherited properties by calling the superclass initializer. At least one designated initializer is defined for every class.

Syntax

Following is the syntax for the designated initializer −

init(parameterList)
{
   // Statement
}

Example

Swift program to demonstrate how to create designated initializers.

// Super class 
class mainClass {
   var no1 : Int 
    
   // Designated Initializer
   init(no1 : Int) {
      self.no1 = no1 
   }
}

// Sub class
class subClass : mainClass {
   var no2 : Int 
    
   // Designated Initializer
   init(no1 : Int, no2 : Int) {
      self.no2 = no2 
        
      // Calling designated initializer of super class to initialize no1
      super.init(no1:no1) 
   }
}

// Creating instances
let obj1 = mainClass(no1: 10)
let obj2 = subClass(no1: 10, no2: 20)

print("no1:", obj1.no1)
print("no1:\(obj2.no1) and no2: \(obj2.no2)")
Output

It will produce the following output −

no1: 10
no1:10 and no2: 20

Convenience Initializer

It is the supporting initialize for a class. It can be implemented to invoke a designated initializer within the same class, wherein certain parameters of the designated initializer are assigned default values. It can also create an instance for a specific use case or input value type. A class doesn't need to have a convenience initializer.

Syntax

Following is the syntax for the convenience initializer −

convenience init(parameterList)
{
   // Statement
}

Example

Swift program to demonstrate how to create convenience initializers.

class mainClass {
   var no1 : Int 
    
   // Designated Initializer
   init(no1 : Int) {
      self.no1 = no1 
   }
}

class subClass : mainClass {
   var no2 : Int
    
   // Designated Initializer
   init(no1 : Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
    
   // Requires only one parameter for convenient method
   override convenience init(no1: Int)  {
      self.init(no1:no1, no2:0)
   }
}

// Creating instances
let obj1 = mainClass(no1: 20)
let obj2 = subClass(no1: 30, no2: 50)

print("res is: \(obj1.no1)")
print("res is: \(obj2.no1)")
print("res is: \(obj2.no2)")
Output

It will produce the following output −

res is: 20
res is: 30
res is: 50

Initializer Inheritance and Overriding

Swift does not allow its subclasses to inherit its superclass initializers for their member types by default. They can call the initializer of its superclass with the help of super.init() to make sure that all the inherited properties are initialized with some values.

We are allowed to override the designated initializer of the superclass in their subclass with the help of the override keyword. The overriding initializer must have to call the corresponding initializer in their superclass with the help of super.init().

As we know a subclass cannot inherit their superclass initialiser by default. However, if the superclass initializers can meet the following condition then they can automatically inherited by their subclasses −

  • If the subclass does not have any designated initializers, then it will automatically inherit its base class’s designated initializers.

  • If the subclass provides the implementation of all its base class’s designated initializers then it will automatically inherit all base class’s convenience initializers.

Example

Swift program to demonstrate how to override initializer.

// Base class
class Sides {
   var corners = 4
   var description: String {
      return "\(corners) sides"
   }
}

// Instance of sides class
let rectangle = Sides()
print("Rectangle: \(rectangle.description)")

// Subclass
class Pentagon: Sides {

   // Overriding initializer
   override init() {
      super.init()
      corners = 5
   }
}

// Instance of Pentagon class
let bicycle = Pentagon()
print("Pentagon: \(bicycle.description)")

Output

It will produce the following output −

Rectangle: 4 sides
Pentagon: 5 sides

Example

Swift program to demonstrate how designated and convenience initializers in action.

class Planet {
   var name: String
    
   init(name: String) {
      self.name = name
   }
    
   convenience init() {
      self.init(name: "[No Planets]")
   }
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")

class planets: Planet {
   var count: Int
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
    
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}

Output

It will produce the following output −

Planet name is: Mercury
No Planets like that: [No Planets]

Failable Initializer

Not all the initializers can initialize values successfully they can fail due to: Invalid parameter values, the absence of a required external source, or a condition preventing initialization from succeeding.

So to catch exceptions thrown by the initialization method, Swift provides a special type of initializer that is a 'failable initializer’. A failable initializer notifies the developer that something is left unnoticed while initializing the structure, class or enumeration members. Or we can say that a failable initializer creates an optional value of type it initializes. If a failure triggers, then this initializer will return nil. A class, structure or enumeration can have one or more failable initializers to catch the fail.

Using the init? keyword we can create a failable initializer. Also, failable and non-failable initializers cannot be defined with the same parameter types and names.

Syntax

Following is the syntax for the failable initializer −

init?(parameterList)
{
   // Statement
}

Example

Swift program to demonstrate how to create failable initializers.

struct studrecord {
   let stname: String
    
   // Failable initializer
   init?(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}

let stmark = studrecord(stname: "Swing")
if let name = stmark {
   print("Student name:\(name) is specified.")
}

let blankname = studrecord(stname: "")
if blankname == nil {
   print("\nStudent name is left blank")
}

Output

It will produce the following output −

Student name:studrecord(stname: "Swing") is specified.

Student name is left blank

Failable Initializers for Enumerations

In Swift, we are allowed to use failable initializers for enumerations too to notify the user when the enumeration members are left from initializing values. It selects proper enumeration cases according to one or more parameters and the initializer can fail if the given parameter does not match to the specified enumeration case.

Example

Swift program to demonstrate failable initializers for enumerations.

// Enumeration
enum functions {
   case a, b, c, d

   // Failable initializer
   init?(funct: String) {
      switch funct {
         case "one":
            self = .a
         case "two":
            self = .b
         case "three":
            self = .c
         case "four":
            self = .d
         default:
            return nil
      }
   }
}

let result = functions(funct: "two")
if result != nil {
   print("With In Block Two")
}
let badresult = functions(funct: "five")
if badresult == nil {
   print("Block Does Not Exist")
}
Output

It will produce the following output −

With In Block Two
Block Does Not Exist

Failable Initializers for Classes

A failable initializer when declared with enumerations and structures alerts an initialization failure at any circumstance within its implementation. However, a failable initializer in classes will alert the failure only after the stored properties have been set to an initial value.

Example

Swift program to demonstrate failable initializers for classes.

// Class
class studrecord {
   let studname: String!
    
   // Failure Initializer
   init?(studname: String) {
      self.studname = studname
      if studname.isEmpty { return nil }
   }
}
if let stname = studrecord(studname: "Failable Initializers") {
   print("Module is \(stname.studname!)")
}
Output

It will produce the following output −

Module is Failable Initializers

Overriding a Failable Initializer

Just like the initializer we are allowed to override a superclass failable initializer inside the subclass. Super class failable initialize can also be overridden within a sub-class non-failable initializer. Subclass initializer cannot delegate up to the superclass initializer when overriding a failable superclass initializer with a non-failable subclass initialize. Whereas a non-failable initializer can never be delegated to a failable initializer.

Example

Swift program to demonstrate overriding failable initializers.

class Planet {
   var name: String
    
   init(name: String) {
      self.name = name
   }
   
   convenience init() {
      self.init(name: "[No Planets]")
   }
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")

class planets: Planet {
   var count: Int
    
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
    
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}
Output

It will produce the following output −

Planet name is: Mercury
No Planets like that: [No Planets]

The init! Failable Initializer

As we know we can create optional failable initializers with the help of init?, they return nil if the initialization process fails, otherwise, they will return an instance of the specified type. So to implicitly unwrapped optional instances swift provides a special type of initializer that is init!. It is used when the failure condition should never happen and if it occurs then the program will crash at run time. We can delegate from init? to init! or vice versa. We can override init? With init! or vice versa.

Example

Swift program to demonstrate init! failable initializers.

struct studrecord {
   let stname: String
    
   // init! initializer
   init!(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")
if let name = stmark {
   print("Student name: \(name) is specified")
}
let blankname = studrecord(stname: "")
if blankname == nil {
   print("Student name is left blank")
}
Output

It will produce the following output −

Student name: studrecord(stname: "Swing") is specified
Student name is left blank

Required Initializers

The required initializer in a class is the initializer that must be implemented by all the subclasses of that class where it is declared. To declare a required initializer using the required keyword, and all the subclass that implements the required initializer must use the required keyword. If we are overriding the required designed initializer, then we do not need to specify the override modifier before the initializer.

Syntax

Following is the syntax for the required initializer −

required init(parameterList)
{
   // Statement
}

Example

Swift program to demonstrate required initializers.

// Superclass
class classA {

   // Required initializer
   required init() {
      let a = 10
      print(a)
   }
}

// Subclass
class classB: classA {

   // Required initializer
   required init() {
      let b = 30
      print(b)
   }
}

// Instance of subclass and superclass
let obj1 = classA()
let obj2 = classB()

Output

It will produce the following output −

10
30
10
Advertisements