Swift Initialization

  • Definition
  • Relationships between designated and convenience initializers
  • Sample code – Designated、Convenience initializers

Definition:

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

Convenience initializers:

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.

Failable Initializers:

To cope with initialization conditions that can fail, define one or more failable initializers as part of a class, structure, or enumeration definition. You write a failable initializer by placing a question mark after the init keyword (init?).
A failable initializer creates an optional value of the type it initializes. You write return nil within a failable initializer to indicate a point at which initialization failure can be triggered.

EX:

class Test4 {
    var input: String
    init?(input: String) {
        guard !input.isEmpty else {
            return nil
        }
        self.input = input
    }
}

if let t4 = Test4(input: "") {
    print("t4.input: \(t4.input)")
} else {
    print("initialization fail")
}

 Relationships between designated and convenience initializers:

Rule 1

– A designated initializer must call a designated initializer from its immediate superclass.

Rule 2

– A convenience initializer must call another initializer from the same class.

Rule 3

– A convenience initializer must ultimately call a designated initializer.

Note:

A simple way to remember this is:

– Designated initializers must always delegate up.

– Convenience initializers must always delegate across.

Sample code – Designated、Convenience initializers:

class Test2 {
    var input: Int
    var input2: String
    init(input: Int, input2: String) {
        print("test2 init - designated")
        self.input = input
        self.input2 = input2
    }
    
    convenience init(input: Int) {
        print("test2 init - convenience")
        self.init(input: input, input2: "test")
    }
}

class Test3: Test2 {
    override init(input: Int, input2: String) {
        print("test3 init - designated")
        super.init(input: input, input2: input2)
        self.input = input / 2
        self.input2 = input2 + "t"
    }
    convenience init(input2: String) {
        print("test3 init - convenience")
        self.init(input: 1, input2: input2)
    }
}

let t2 = Test2(input: 3)
// Console output:
// test2 init - convenience
// test2 init - designated
let t3A = Test3(input: 1, input2: "a")
// Console output:
// test3 init - designated
// test2 init - designated
let t3B = Test3(input2: "Check")
// Console output:
// test3 init - convenience
// test3 init - designated
// test2 init - designated

Ref: https://docs.swift.org/swift-book/LanguageGuide/Initialization.html