Tutorials  /  Python

Swift init()

Ccentron Redaktion · January 2024 ·10 min read ·Python, Tutorial

In this Swift init() tutorial, we’ll be discussing an important concept, namely Swift init or Swift initialization. Initialization is what happens when we create an instance of some type.

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.

Initializers are similar to constructors in java programming. Swift being a type-safe language has placed a lot of rules for initializers. It can get tricky to implement unless you’ve got a good hold of the concept.

Swift init() Syntax

Code
init() {
    // initialise the stored properties here.
}

Let’s look at a sample class below.

Code
class A{
    //Compilation error. No initializer is defined.
    var a : Int
    var b : String
    var c : Int?
    let website = "JournalDev"
}

Above class won’t compile. The swift compiler complains that the stored properties aren’t initialized. Stored Properties can’t be kept in an undetermined state. This leaves us with two possible options:

  1. Assign a default property value in the property definition itself.
  2. Use an initializer, init() for initializing the properties.

Let’s look at each of the approaches one at a time.

Code
class A{
    var a : Int = 5
    var b : String = "Hello. How you're doing"
    var c : Int?
    let website = "JournalDev"
}

Here we’ve set a default value for each of the stored properties, hence Swift provides us the default initializer implicitly. All the properties and functions can be accessed using the dot operator over an instance of the class once it’s initialized.

Code
var object = A()
object.a = 10
object.c = 2

The second way is to initialize the stored properties using the init() method as shown below.

Code
class A{
    var a : Int
    var b : String
    var c : Int?
    let website = "JournalDev"
    
    init(a: Int, b: String) {
        self.a = a
        self.b = b
    }
}

var object = A(a: 5, b: "Hello World")

Note: Swift Optional is not a stored property. Hence, they need not be initialized. Stored properties are accessed inside the init() method using self property. Note: self is used to refer to the current instance within its own instance methods (Similar to this in java). The above initializer is the primary initializer of the class. It’s also known as designated initializer (we’ll discuss this later). Initializers lets us modify a constant property too.

Code
class A{
    
    var a : Int
    var b : String
    var c : Int?
    let website : String
    
    init(a: Int, b: String, website: String) {
        self.a = a
        self.b = b
        self.website = website
    }
}

var object = A(a: 5, b: "Hello World", website: "JournalDev")
VM

Matching infrastructure at centron

Scripts and services eventually need an environment that keeps running: ccloud³ VMs from €3.12 per month, billed by the hour. Rent a cloud server →

Memberwise Initializers for Structures

Structures being value types, don’t necessarily require an initializer defined. Structure types automatically receive a memberwise initializer unless you’ve defined custom initializer(s). Following are the code snippets that describe the various ways to initialize a struct.

Code
struct Rect{
    var length : Int
    var breadth : Int
}
var r = Rect(length: 5, breadth: 10)
Code
struct Rect{
    var length : Int = 5
    var breadth : Int = 10
}

var r = Rect()
var r1 = Rect(length: 10, breadth: 5)

Since we’ve assigned default values to the stored properties in the above snippet, we receive a default initializer without member initialization alongwith the memberwise initializer.

Code
struct Rect{
    var length : Int
    var breadth : Int
    
    init(length: Int, breadth: Int) {
        self.length =  length + 10
        self.breadth = breadth + 10
    }
}
var r = Rect(length: 10, breadth: 5)

In the above case, we’ve defined our own custom initializer. Using Parameters without External Name When an external name is not needed for an initializer, underscore ‘_’ is used to indicate the same as shown below.

Code
class A{
    
    var a : Int
    var b : String
    var c : Int?
    let website = "JournalDev"
    
    init(_ a: Int, _ b: String) {
        self.a = a
        self.b = b
    }
}

var object = A(5,"Hello World")
Code
struct Rect{
    var length : Int
    var breadth : Int
    
    init(_ length: Int, _ breadth: Int) {
        self.length =  length + 10
        self.breadth = breadth + 10
    }
}
var r = Rect(10, 10)

Types of Swift Initializers

Initializers for classes can be broadly classified into the following types:

    1. Designated Initializers: This is the primary initializer of the class. It must fully initialize all properties introduced by its class before calling any superclass initializer. A class can have more than one designated initializer. Every class must have at least one designated initializer.
    2. Convenience Initializers: These are secondary, supporting initializers for a class. They must call a designated initializer of the same class. These are optional and can be used for a custom setup. They are written in the same style, but with the convenience modifier placed before the init keyword.
Code
class Student{
    var name : String
    var degree : String
    init(name : String, degree: String) {
        self.name = name
        self.degree = degree
    }
    convenience init() {
        self.init(name: "Unnamed", degree: "Computer Science")
    }
}
var student = Student()
student.degree // "Computer Science"
student.name // "Unnamed"

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

Swift Initializer Delegation For Value Types

It’s possible to call an initializer from another one thereby avoiding code duplication. Value Types like Structures do not support inheritance. Hence the only possible way is to call initializer within the same structure. An example is given below.

Code
struct Rect{
    var length : Int
    var breadth : Int
    init(_ length: Int, _ breadth: Int) {
        self.length = length
        self.breadth = breadth
    }
    init(_ length: Int) {
        self.init(length, length)
    }
}
var r = Rect(10, 5)
var r1 = Rect(15) //initialises the length and breadth to 15

Swift Initializer Delegation For Reference Types

Classes being reference types support inheritance. Thus initializers can call other initializers from superclass too thereby adding responsibilities to properly inherit and initialize all values. Following are the primary rules defined for handling relationships between initializers.

      • A designated initializer must call a designated initializer from its immediate superclass.
      • A convenience initializer must call another initializer from the same class.
      • A convenience initializer must ultimately call a designated initializer.

Designated initializers must always delegate up. Convenience initializers must always delegate across. super keyword is not possible for a convenience initializer in a subclass.

Swift Initializer Inheritance and Overriding

Subclasses in Swift do not inherit their superclass’s initializers by default unless certain conditions are met (Automatic Initializer Inheritance). This is done to prevent half-baked initialization in the subclass. Let’s look at how designated and convenience initializers work their way through inheritance. We’ll be defining a Vehicle base class that’ll be inherited by the relevant subclasses. We’ll use Enums as a type in the classes. Our base class Vehicle is defined as shown below.

Python
enum VehicleType : String {
    case twoWheeler = "TwoWheeler"
    case fourWheeler = "FourWheeler"
}
class Vehicle{
    var vehicleType : VehicleType
    init(vehicleType: VehicleType) {
        self.vehicleType = vehicleType
        print("Class Vehicle. vehicleType is \(self.vehicleType.rawValue)\n")
    }
    convenience init() {
        self.init(vehicleType: .fourWheeler)
    }
}
var v = Vehicle(vehicleType: .twoWheeler)

Note: The convenience initializer must call the designated initializer of the same class using self.init Let’s define a subclass of the above class as shown below.

Python
enum TwoWheelerType : String {
    case scooty = "Scooty"
    case bike = "Bike"
}

class TwoWheeler : Vehicle{
    var twoWheelerType : TwoWheelerType
    var manufacturer : String
    
    init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
        super.init(vehicleType: vType)
    }
}

Important points to note:

      • The designated initializer of the subclass must initialize its own properties before calling the designated initializer of the superclass.
      • A subclass can modify inherited properties of the superclass only after the super.init is called.

Following code would lead to a compile-time error.

Code
class TwoWheeler : Vehicle{
    
    var twoWheelerType : TwoWheelerType
    var manufacturer : String
    
    init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        self.vehicleType = vType //Won't compile
        super.init(vehicleType: vType)
        //self.vehicleType = .fourWheeler //This would work.
        
    }
}

var t = TwoWheeler(twoWheelerType: .scooty, manufacturer: "Hero Honda", vType: .twoWheeler)

As explained earlier, the superclass initializer isn’t inherited automatically in the subclass. So the below initialization would fail.

Code
var t = TwoWheeler(vehicleType: .twoWheeler) // manufacturer property isn't initialized.

To override an initializer, the subclass initializer must match with the designated initializer of the superclass. The override keyword is appended to the initializer in this case.

Python
class TwoWheeler : Vehicle{
    
    var twoWheelerType : TwoWheelerType
    var manufacturer : String
    
    init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
        super.init(vehicleType: vType)
        
    }
    
    override init(vehicleType: VehicleType)
    {
        print("Class TwoWheeler. Overriden Initializer. \(vehicleType.rawValue)")
        self.twoWheelerType = .bike
        self.manufacturer = "Not defined"
        super.init(vehicleType: vehicleType)
    }

The below initializer doesn’t override the one from superclass since the parameter name is different.

Code
//This would give a compile-time error since the parameter v doesn't match with the superclass.
override init(v: VehicleType)
    {
        self.twoWheelerType = .bike
        self.manufacturer = "Not defined"
        super.init(vehicleType: v)
    }

Using Convenience Initializer to override the one from superclass.

Python
class TwoWheeler : Vehicle{
    
    var twoWheelerType : TwoWheelerType
    var manufacturer : String
    
    init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
        super.init(vehicleType: vType)
        
    }
    
    override convenience init(vehicleType: VehicleType) {
        self.init(twoWheelerType: .bike, manufacturer: "Not Defined", vType: .twoWheeler)
        self.vehicleType = vehicleType
    }
}
var t = TwoWheeler(twoWheelerType: .scooty, manufacturer: "Hero Honda", vType: .twoWheeler)
t = TwoWheeler(vehicleType: .twoWheeler)

//Output
Following gets printed on the console:
Class TwoWheeler. Scooty manufacturer is Hero Honda
Class Vehicle. vehicleType is TwoWheeler

Class TwoWheeler. Bike manufacturer is Not Defined
Class Vehicle. vehicleType is TwoWheeler

The convenience initializer has override keyword appended to it. It calls the designated initalizer of the same class. Note: The order of the keywords convenience and override doesn’t matter.

Required Initializers

Writing the keyword required before the initializer indicates that each subclass must implement that initializer. Also, the required modifier must be present at the respective subclass implementations as well. An example of Required Initializers on the above two classes is given below.

Python
class Vehicle{
    
    var vehicleType : VehicleType
    
    required init(vehicleType: VehicleType) {
        self.vehicleType = vehicleType
        print("Class Vehicle. vehicleType is \(self.vehicleType.rawValue)\n")
    }
    
    convenience init()
    {
        self.init(vehicleType: .fourWheeler)
    }
}

class TwoWheeler : Vehicle{
    
    var twoWheelerType : TwoWheelerType
    var manufacturer : String
    
    init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
        super.init(vehicleType: vType)
        
    }
    
     required init(vehicleType: VehicleType) {
        self.manufacturer = "Not Defined"
        self.twoWheelerType = .bike
        super.init(vehicleType: vehicleType)
    }
}

Note: Adding a required modifier indicates that the initializer would be overridden. Hence the override keyword can be omitted in the above case. Using a Required Initializer with Convenience Required and convenience initializers are independent of each other and can be used together. Let’s create another subclass of Vehicle to demonstrate the use of required and convenience modifiers together.

Python
enum FourWheelerType : String {
    case car = "Car"
    case bus = "Bus"
    case truck = "Truck"
}

class FourWheeler : Vehicle {
    var fourWheelerType : FourWheelerType
    var name : String

    init(fourWheelerType : FourWheelerType, name: String, vehicleType: VehicleType) {
        self.fourWheelerType = fourWheelerType
        self.name = name
        print("Class FourWheeler. \(self.fourWheelerType.rawValue) Model is \(self.name)")
        super.init(vehicleType: vehicleType)
        self.vehicleType = vehicleType
    }

    required convenience init(vehicleType: VehicleType) {
        self.init(fourWheelerType: .bus, name: "Mercedes", vehicleType: vehicleType)
    }
}

class Car : FourWheeler {
    var model : String

    init(model: String) {
        self.model = model
        print("Class Car. Model is \(self.model)")
        super.init(fourWheelerType: .car, name: self.model, vehicleType: .fourWheeler)
    }

    required init(vehicleType: VehicleType) {
        self.model = "Not defined"
        print("Class Car. Model is \(self.model)")
        super.init(fourWheelerType: .car, name: self.model, vehicleType: vehicleType)
    }
}

Important things to note in the above code snippet:

      • Convenience initializers are secondary initializers in a class.
      • Setting a convenience initializer as required means that implementing it in the subclass is compulsory.

Automatic Initializer Inheritance

There are two circumstances under which a subclass automatically inherits the initializers from the superclass.

      • Don’t define any designated initializers in your subclass.
      • Implement all the designated initializers of the superclass. All the convenience initializers would be automatically inherited too.

The first rule in action is demonstrated in the snippet below:

Code
class Name {
    var name: String

    init(n: String) {
        self.name = n
    }
}

class Tutorial: Name {
    var tutorial : String? = "Swift Initialization"
}

var parentObject = Name(n: "Anupam")
var childObject = Tutorial(n: "JournalDev")

The second rule in action is demonstrated in the snippet below.

Python
class Name {
    
    var name: String
    
    init(n: String) {
        self.name = n
    }
    
    convenience init()
    {
        self.init(n: "No name assigned")
    }
}

class Tutorial: Name {
    
    var tutorial : String? = "Swift Tutorial"
    
    override init(n : String) {
        super.init(n: n)
    }
}

var parentObject = Name(n: "Anupam")
var childObject = Tutorial(n: "JournalDev")
var childObject2 = Tutorial()
print(childObject2.name) //prints "No name assigned

The convenience initializer of the superclass is automatically available in the subclass in the above code.

Swift Failable Initializer

We can define a failable initializer using the keyword init? on Classes, Structures, or Enumerations which gets triggered when the initialization process fails. Initialization can fail for various reasons: Invalid parameter values, absence of an external source, etc. A failable initializer creates an optional value of the type it initializes. We’ll be returning a nil to trigger an initialization failure (Though an init doesn’t return anything).

Failable Initializers With Structures

Python
struct SName {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

var name = SName(name: "JournalDev")
if name != nil {
    print("init success") //this gets displayed
}
else{
    print("init failed")
}
name  = SName(name: "")

if name != nil {
    print("init success")
}
else{
    print("init failed") //this gets displayed
}

Failable Initializers With Enums

Python
enum CharacterExists {
    case A, B
    init?(symbol: Character) {
        switch symbol {
        case "A":
            self = .A
        case "B":
            self = .B
        default:
            return nil
        }
    }
}


let ch = CharacterExists(symbol: "C")
if ch != nil {
    print("Init failed. Character doesn't exist")
}
Python
class CName {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}
var name  = CName(name: "")

if name != nil {
    print("init success")
}
else{
    print("init failed")
}

Note: A failable initializer and a non-failable initializer can’t have the same parameter types and names.

Overriding a Failable Initializer

You can override a failable initializer in your subclass. A failable initializer can be overridden with a non-failable initializer but it cannot happen vice-versa. An example of overriding a failable with a non-failable initializer is given below.

Code
class CName {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}
var name = CName(name: "")

class SubName : CName {
    var age: Int
    override init(name: String) {
        self.age = 23
        super.init(name: name)!  
    }
}

Note: Forced unwrapping is used to call a failable initializer from the superclass as part of the implementation of a subclass’s nonfailable initializer. This brings an end to swift init tutorial.

Jetzt 200 € Guthaben sichern

Testen Sie Ihr Setup auf ccloud³

Registrieren Sie sich in der ccloud³ und erhalten Sie 200 € Startguthaben für Ihr Projekt – z. B. für eine PostgreSQL-VM mit automatischen Backups.

centron Redaktion Technische Redaktion

Das Redaktionsteam von centron schreibt Anleitungen aus dem Betriebsalltag: getestet auf unserer eigenen Plattform, betrieben im Rechenzentrum in Hallstadt bei Bamberg.

Kategorie Python
Teilen
Noch offene Fragen?

Unser Team hilft Ihnen bei Ihrem konkreten Setup weiter – von Menschen, die die Plattform selbst betreiben.

War dieses Tutorial hilfreich?

Ihre Antwort wird anonym gespeichert und hilft uns, die Tutorials zu verbessern.

Kommentare

Noch keine Kommentare – stellen Sie die erste Frage zu diesem Tutorial.

Zum Kommentieren anmelden

Kommentare stehen centron-Kunden offen. Melden Sie sich in Ihrem Konto an, um eine Frage zu diesem Tutorial zu stellen.

Weiterlesen

Das könnte Sie auch interessieren

Jetzt kostenlos anfangen

Melden Sie sich an und erhalten Sie in den ersten 60 Tagen ein Guthaben von 200 € bei centron.

Dieses Werbeangebot gilt nur für neue Konten. Angebot ausschließlich für Gewerbetreibende.

Jetzt loslegen Sales kontaktieren