Saturday, June 21, 2014

Initializers in Swift Programming Language

As the name says Initialization. Initializers are declared to set the initial values of the type when any object of type gets initialized. Initializers are declared using the the syntax

init() {…}

you can also pass parameters to the initializers. So As the Swift programming enforces one simple rule

“Every value must be initialized before it is used”

Only exception to the above rule is optionals where we default their vale to nil. 

So what the above rule means? Does it mean that I cannot write something like

var someString : String

No, It means before you access any value it must be initialized in every possible branch of the execution of the code. If you don’t do it you will get a compile time error. Initializers have the responsibility to fully initialize an instance.

Initializers in Structure

So if you have a structure like this

struct Person
{
    var firstName : String
    var LastName: String
    init(first: String, last: String)
    {
        firstName = first
        lastName = last
    }
}
  • Say you forgot to initialize the firstName in the initiazer, than compiler will generate a compile time error.
  • Also if you try to call any method before initializing all the variables in the struct, you will get a compile time error.
  • you can write initializers for Structures and Classes both.


Memberwise Initializer

What if you do not specify any Initializer to the struct or class? 

Swift Compiler provide you with a Memberwise initializer. So for the above structure if you do not have the initializer declared you can still initialize the values by saying

var karm = Person(firstName: “Karmjit”, lastName: “Singh”)

Class Initializer


Class initializers are no different from the struct. However, we have class hierarchies we need to initialize the super class while initializing the sub class. When all the classes in the hierarchy are initialized than you can say that the class is initialized.

The order of initialising the classes is that first the sub class is initialized and than it calls super class initializer.

If you are coming from the Objective C background than you must have noticed that it is different from how class initialization use to be done in objective C. In Objective C you initialize your super class properties first and than the sub class properties.

But, if you try to do this in Swift you will get a compile time error. So why does this order needs to be changed?

Because it ensures the Memory safety, you do not want to access the instance before it is completely initialized. Initializing the super class first you may not be obviously running into any problem. but lets take an example.

class Car{
    var carModel: String
    func fillTank(){
        
    }
    init(color: String){
        carModel = color
        fillTank()
    }
}

class RaceCar : Car{
    var raceCarModel: String
    
    override func fillTank() {
        
    }
    
    init(color: String, raceCarModel: String) {
        self.raceCarModel = raceCarModel
        super.init(color: color)
    }
}

now in the above example what happen if you move the super.init above the self.raceCarModel = raceCarModel line 

super.init will call the super class initializer and which is call method fillTank from its initializer and now fill tank is overridden in the sub class which get called and at that our sub class is not yet initialized. 

This is what was different from Objective C. 
  • you can still have multiple initiazer as you do in Objective C.
  • You can have designated initializers whose sole responsibility is setting an object and initializing its properties.
  • You can also have convenience initializers. Convenience initializers can be called in the classes they cannot call the super class initializers. They can call the designated initializers.

Convenience Initializer


class Car{
    var carModel: String
    var turboMode: Bool
    
    func fillTank(){
        
    }
    init(color: String, turboMode: Bool){
        carModel = color
        self.tuboMode = turboMode
        fillTank()
    }
    
    convenience init(color: String){
        self.init(color: color, turboMode: true)
    }    
}

Initializer Inheritance 


How initializers are inherited in swift? 
  • They are not inherited by default. 
  • If you do not specify any initializer for the class and you set the default values of all the instance variables in the class than you automatically inherit all the super class initializer including both designated and the convenience.

we have see the initialization of the classes and structures. If you have noticed we have discussed how do we initialize our classes using designated and convenience initializers. How about you do not want to initialize a property in the class or something like that. What we usually call lazy loading. 

Swift comes up with… 

Lazy Properties


If you have a property that takes lot of computation while initialization and you do not want to initialize the property until it is accessed. so you declare that property with @lazy attribute in front of the property. 

class MultiPlayer{
    //.....
}

class Game {
    @lazy var multiplayer = MultiPlayer()
    var singlePlayer : Bool
    init(){
        singlePlayer = true
    }
}

Deinitialization


As the memory management in Swift is automatic. So we do not have to actually worry about the deinitialization of the objects. But in some scenarios like you want to close an observer, or close an open connection to database or close an open file.

Deinitializer are declared using deinit keyword.

So what we have learned in this whole article?
  • Initialize all the values before you use them.
  • Set the class properties first and than call super.init.
  • Designated initializers are called only up.
  • Convenience initializers are called across.

 I hope now you have some level of understanding of Initializers in Swift....

Happy Coding!!!

No comments:

Post a Comment