Swift-Initializer

Posted by ewillms on Thu, 03 Mar 2022 19:29:22 +0100

Convenient Initialization

Previous initializers were called specified initializers (required, no system will generate a default), and convenient initializers

Uses of convenient initializers

The specified initializer is not to be overlooked. The convenience initializer does work with the specified initializer in the data I have available at this time. In addition, the convenience initializer cannot be used in the structure.

class Person {
    var a:Int,b:Int
    init(a:Int,b:Int) {
        self.a = a
        self.b = b
    }
    
    convenience init(a:Int)
    {
        self.init(a:a,b:10)
    }
}

For example, this initializer has two scenarios where a and B both have values and one only needs to be assigned. In this case, there are actually two choices, 1. Write multiple specified initializers, 2. Write one specified initializer and multiple convenient initializers

Generally speaking, the recommended writing is a specified initializer + multiple convenient initializers, so that the structure inside the inheritance is clearer (explained in the inheritance), and that the same initializer is called locally. Some uniform settings can also be written together

class Person {
    var a:Int,b:Int
    init(a:Int,b:Int) {
        self.a = a
        self.b = b
    }
    convenience init(a:Int)
    {
        self.init(a:a,b:10)
    }
    convenience init(b:Int)
    {
        self.init(a:10,b:b)
    }
    convenience init()
    {
        self.init(a:10,b:10)
    }
}

For example, in this particularly complex case, if you need to set something to this class, the Write Instruction Initializer has to write all the settings in these four cases (since the Instruction Initializer can only adjust the Instruction Initializer of the parent class, not the same class).

Instruction Initializer and Convenient Initializer Use Within Inheritance

In inheritance, it is generally only a command initializer call, not a convenient initializer

So the general recommendation when inheriting is

The same class, multiple convenient initializers, one specified initializer, unless it is final class, it is not recommended to write more than one specified initializer, otherwise there will be dozens of initialization combinations, which directly make it dizzy, bad for module design, and difficult to maintain later. Like this mode, convenient initializers can only find initializers of this class. Instruction Initializer then looks for Instruction Initializer of the parent class so that inheritance is a line and can be varied locally

Inter-Initializer Call Rules

Convenient Initializer can only call Convenient Initializer and Instruction Initializer of this class

Instruction initializer can only call instruction initializer of parent class

Two-Segment Initialization

I always encounter when I just wrote code

self.c = c

super.init(a: a, b: b)

Writing this code in the wrong order can cause problems such as errors because of two initializations

Stage 1: Initialize all storage properties

1. Outer Call Initializer ------ is the Outer Call Initializer

2. Allocate storage but not initialize -------------- Initialization begins after outer layer call, first malloc, where only space is allocated but not actually initialized

3. Specify an initializer to ensure that all storage properties can be initialized --------- that is, specify an initializer to initialize all storage properties

4. Call the parent initializer, and keep going up to form the initializer chain ------------------- If the initializer of this class is not sufficient to initialize all the storage properties, call the initializer of the parent class as self.c = c must be written in super. Before init()

So the purpose of the first phase is to ensure that all storage properties can be initialized

class Person {
    var a:Int,b:Int
    init(a:Int,b:Int) {
        self.a = a
        self.b = b
    // end
    }
    convenience init(a:Int)
    {
        self.init(a:a,b:10)
    }
    convenience init(b:Int)
    {
        self.init(a:10,b:b)
    }
    convenience init()
    {
        self.init(a:10)
        self.b = 10
        
    }
}

class Teacher: Person {
    var c:Int
    init(a: Int, b: Int, c: Int) {
        self.c = c
        super.init(a: a, b: b)
    }
    convenience init(a:Int)
    {
        self.init(a: a, b: 2,c: 5)
    }
}
Person(a:10)

Like this code, suppose initializing a Person goes through the convenient initializer int(a:Int), then initializes c to the instruction initializer, then invokes the instruction initializer of the parent class to initialize a, and then the first phase of initialization ends

Stage 2: Setting new storage property values

It feels like initialization is finished after the first stage, and everything else inside the initializer can be executed, so self. Functions cannot be written before the first phase of initialization, such as

class Teacher: Person {
    var c:Int
    init(a: Int, b: Int, c: Int) {
        self.ptr()
        self.c = c
        super.init(a: a, b: b)
        self.ptr()
    }
    convenience init(a:Int)
    {
        self.init(a: a, b: 2,c: 5)
    }
    
    func ptr() {
        print("sth")
    }
}

self.ptr is written on self.c = c This line is preceded by an error because the first phase of initialization has not completed self. Functions are meaningless

Security check

1. The subclass storage object must be initialized before the parent class can be invoked, because the initializer of the parent class cannot initialize the subclass storage property, that is, self. Property initialization such as C = C must be written in super. Before init

2. Even if the subclass assigns values to the parent's storage properties, the parent's initializer must be invoked first

For example, this self.a = a is an error because the first stage initialization of the parent class has not been completed or even invoked

Convenient initializers also have to have the specified initializers initialized before they can be manipulated

In short, you cannot use self in an initializer until one phase of initialization is complete. Do everything except initialization, and local initialization must take precedence

Override Initializer

Parameter return value is the same, content is biased is overridden

class Person {
    var a:Int,b:Int
    init(a:Int,b:Int) {
        self.a = a
        self.b = b
    }
}
class Teacher: Person {
    var c:Int
    init(a: Int, b: Int, c: Int) {
        self.c = c
        super.init(a: a, b: b)
    }
    override init(a:Int,b:Int) {
        self.c = 10
        super.init(a: a, b: b)
    }
}

It seems that overriding an initializer is not very meaningful, because c still needs to be assigned a value, and it can become more complex to use in inheritance. It is worth noting that subclasses cannot override the convenient initializer of a parent class

In addition, if the subclass does not write an initializer, it automatically inherits all the instruction initializers of the parent class, and the individual feels that unless the subclass has no storage properties, it will write an initializer

Topics: Swift