Swift - Initializer & Deinitializer
Tags: swift, beginners, programming, tutorial
Published: 2022-01-05 12:17:33

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,

```swift
struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 32.0
    }
}

var f = Fahrenheit()
f.temperature //32.0
```
## Parameterized Initializer
A Swift initializer can also accept one or more parameters. Such initializers are known as parameterized initializers (initializers with parameters).

```swift
struct Fahrenheit {
    var temperature: Double
    init(temp:Double) {
        self.temperature = temp
    }
}

var f = Fahrenheit(temp:45)
f.temperature //45.0
```

## 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.

```swift
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)
let halfGray = Color(white: 0.5)

```
If you don’t 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.

## Optional Property Types
If your custom type has a stored property that’s logically allowed to have “no value”—perhaps because its value can’t be set during initialization, or because it’s allowed to have “no value” at some later point—declare the property with an optional type.

```swift
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()
// Prints "Do you like cheese?"
```

## 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.

```swift
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())
```
## 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,

```swift
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()
//convenience init is called
print(university1.name)
print("Rank:", university1.rank)

```
## 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.

```swift
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
}
```
 
Refer docs for in-depth explanation of this concept.
[swift-Initializer](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html)

## 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.

```swift
deinit {
    // perform the deinitialization
}
```

Swift automatically deallocates your instances when they’re no longer needed, to free up resources. Swift handles the memory management of instances through automatic reference counting ARC (Automatic Reference Counting). Typically you don’t need to perform manual cleanup when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional cleanup yourself. For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.