Initializers and Deinitializers - Swift Programming Language

1.Initializers

  • Initialization is the process of preparing an instance of a class, structure, or enumeration for use.
  • This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready for use.
  • Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.
  • An initializer is like an instance method with no parameters, written using the init keyword:
init() {
    // perform some initialization here
}

Example:

Structure

struct Name {
    var fName: String
    var lNAme: String
    init() {
        fName = "Vineeta"
        lNAme = "Bajaj"
    }
}
var name = Name()
print("Name is \(name.fName) \(name.lNAme)")

//prints: Name is Vineeta Bajaj

Class

class Addition{
    var firstVar: Int
    var secondVar: Int
    init(first: Int, second: Int){
        firstVar = first
        secondVar = second
    }
}

var add = Addition(first: 40, second: 50)
print("Addition is :(add.firstVar + add.secondVar)")

// prints: Addition is: 90

1.1. Default Property Values

  • You specify a default property value by assigning an initial value to the property when it is defined.
struct Fahrenheit {
    var temperature = 32.0
}
var f = Fahrenheit()
print("Temperature is\(f.temperature)")

//prints Temperature is 32.0

1.2. Customizing Initialization

  • You can customize the initialization process with input parameters and optional property types, or by assigning constant properties during initialization.
struct Celsiuss {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsiuss(fromFahrenheit: 212.0)
print("boilingPointOfWater.temperatureInCelsius: \(boilingPointOfWater.temperatureInCelsius)")

let freezingPointOfWater = Celsius(fromKelvin: 273.15)
print("freezingPointOfWater.temperatureInCelsius: \(freezingPointOfWater.temperatureInCelsius)")

/* prints: 
boilingPointOfWater.temperatureInCelsius: 100.0
freezingPointOfWater.temperatureInCelsius: 0.0
*/

1.3. Parameter Names and Argument Labels

  • As with function and method parameters, initialization parameters can have both a parameter name for use within the initializer’s body and an argument label for use when calling the initializer.
struct Color {
    let red, green, blue: Double
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
print(magenta)
let halfGray = Color(white: 0.5)
print(halfGray)

/* prints:
Color(red: 1.0, green: 0.0, blue: 1.0)
Color(red: 0.5, green: 0.5, blue: 0.5)
*/

1.4. Initializer Parameters Without Argument Labels

  • If you do not want to use an argument label for an initializer parameter, write an underscore (_) instead of an explicit argument label for that parameter to override the default behavior.
struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
let bodyTemperature = Celsius(37.0)
print(bodyTemperature)

// prints: Celsius(temperatureInCelsius: 37.0)

1.5. Optional Property Types

  • If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type.
  • Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.
class SurveyQuestion {
    var text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
cheeseQuestion.response = "Yes, I do like cheese."

// prints: Do you like cheese?

1.6. Assigning Constant Properties During Initialization

  • You can assign a value to a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes.
class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
beetsQuestion.response = "I also like beets."

// prints: "How about beets?"

2. Default Initializers

  • Swift provides a default initializer for any structure or class that provides default values for all of its properties and does not provide at least one initializer itself.
  • The default initializer simply creates a new instance with all of its properties set to their default values.
class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()
print("Quantity: \(item.quantity)")

// prints: Quantity: 1

2.1. Memberwise Initializers for Structure Types

  • Structure types automatically receive a memberwise initializer if they do not define any of their own custom initializers.
  • Unlike a default initializer, the structure receives a memberwise initializer even if it has stored properties that do not have default values.
struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
print("width:\(twoByTwo.width), height:\(twoByTwo.height)")

// prints: width:2.0, height:2.0

3. Designated Initializers and Convenience Initializers

  • Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.
    Format of Designated Initializers
init(parameters) {
    statements
}
  • Example of Designated Initializers
// 3.2 Designated Initializers

class Food {
    var name: String
    init(name: String) {
        self.name = name
    }
    convenience init() {
        self.init(name: "[Unnamed]")
    }
}
let namedMeat = Food(name: "Bacon")
print(namedMeat.name)

class RecipeIngredient: Food {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    override convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}

let oneMysteryItem = RecipeIngredient()
print(oneMysteryItem.name)
let oneBacon = RecipeIngredient(name: "Bacon")
print(oneBacon.name)
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
print(sixEggs.quantity)
/* prints:
Bacon
[Unnamed]
Bacon
6 
*/
  • Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.
    Format of Convenience Initializers
convenience init(parameters) {
    statements
}
  • Example of convenience initializers
class Human {
    var name: String
    init(name: String) {
        self.name = name
    }
    
    // Convenience init intializes the designated init method
    convenience init() {
        self.init(name: "Bob Lee")
    }
}
let human = Human()
print(human.name)

// prints: Bob Lee

4. Failable Initializers

  • It is sometimes useful to define a class, structure, or enumeration for which initialization can fail.
  • This failure might be triggered by invalid initialization parameter values, the absence of a required external resource, or some other condition that prevents initialization from succeeding.
  • You write a failable initializer by placing a question mark after the init keyword (init?).
struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}
let anonymousCreature = Animal(species: "")
 
if anonymousCreature == nil {
    print("The anonymous creature could not be initialized")
}

// prints: "The anonymous creature could not be initialized"


5. Deinitialization

  • A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how initializers are written with the init keyword.
  • Deinitializers are only available on class types.
  • Format of deinitialization
deinit {
    // perform the deinitialization
}
  • Example of deinitialization
class SumUp{
    var varA: Int = 0
    var varB: Int = 0
    init(){
        varA = 20
        varB = -20
        print("Value of VarA and VarB after init : \(varA) , \(varB)")
    }
    
    deinit{
        print("Value of VarA and VarB after deinit : \(varA) , \(varB)")
    }
}

func createSumObj(){
let sum = SumUp()
}

createSumObj()

/* prints: Value of VarA and VarB after init : 20 , -20
Value of VarA and VarB after deinit : 20 , -20
*/

You can download the swift playground of all above examples from Here



You've successfully subscribed to Developer Insider
Great! Next, complete checkout for full access to Developer Insider
Welcome back! You've successfully signed in
Success! Your account is fully activated, you now have access to all content.