The original link

The constructor

The constructor is a special function declared using the reserved keyword init. So the constructor function does not need to use the keyword func. Typically, the constructor also does not return any value. The constructor needs to set the initial value for each storage property in the instance.

Note:

When default values are assigned to stored properties or initial values are set in the constructor, their values are set directly without triggering any property observer.

Constant attribute assignment during construction

A constant property can be assigned during construction, as long as the property is set to a certain value at the end of the construction process. Once a constant property is assigned, it can never be changed.

Note:

For instance classes, their constant properties can only be modified during construction of the class that defines them, not in subclasses.

Default constructor

Class or structure If all attributes have default values and there is no custom constructor, Swift provides a default constructor for the structure/class that creates an instance object with all attributes as default values. Examples are as follows:

class TestDefault {
    var title = "test"
    var number = 1
}

var t = TestDefault()
print(t.title,t.number)
Copy the code

Output:

test 1
Copy the code

Here, TestDefault() uses the default constructor.

The default constructor cannot be used when an attribute in a class is not initialized, as follows:

class TestDefault {
    var title = "test"
    var number = 1
    var x: Int
}
Copy the code

Compilation error with the following error message:

Class 'TestDefault' has no initializers
Copy the code
Member by member constructor

In addition to the default constructor, the structure also provides a member-by-member constructor. If you do not provide your own constructor, the compiler will automatically generate a one-member constructor for the structure.

As follows:

struct Person {
    var name: String
    var age: Int
}

var p = Person(name: "Jim", age: 18)

Copy the code

The Person structure does not implement a constructor; compile-time provides a member-by-member constructor for it. A member-by-member constructor takes each attribute as an argument.

Specifying the constructor

All storage properties in a class, including all properties inherited from the parent class, must be set to their initial values during construction. Swift provides two constructors for class types to ensure that all storage properties in an instance get their initial values, the specified constructor and the convenience constructor.

A class must have at least one specified constructor, which is the primary constructor in the class. In general, one specified constructor is sufficient, although there is nothing wrong with declaring multiple specified constructors.

The syntax for specifying the constructor is as follows:

init {
    // statement
}
Copy the code

Use the keyword init.

The specified constructor is the primary constructor of the class, and all properties are initialized in the specified constructor.

Convenience constructor

The syntax for the convenience constructor is as follows:

convenience init {
    // statement
}
Copy the code

Use convenience before the init keyword.

A class may or may not have a convenience constructor, and there is no restriction on that. A convenience constructor, by definition, is intended to facilitate construction. In a convenience constructor, parameters are usually assigned to default values.

Specify the principles for using constructors and convenience constructors

Swift specifies the principles for using specified constructors and convenience constructors as follows:

  1. A specified constructor must call a specified constructor of its parent class
  2. A convenience constructor must call another constructor of the class itself (this can be either the specified constructor or the convenience constructor)
  3. A convenience constructor must eventually call a specified constructor

An easy way to remember:

  1. Specify that the constructor is always propped up
  2. Convenience constructors are always horizontal proxies

The above rules can be illustrated with the following image:

Two-stage structural process

The Swift class uses a two-step construction process with the following steps:

  1. Each storage property in a class gets an initial value, that is, the property is initialized
  2. Give each class an opportunity to further customize the values of the storage properties before new instances are ready for use

The main difference from Objective-C is that OC does not assign any properties and is initialized to nil or 0 by default, whereas Swift has all properties specified by the developer.

The Swift compiler performs four checks to ensure that the two-part construction process completes correctly:

  1. The specified constructor initializes all properties of its own class before calling the specified constructor of its parent class
  2. Specifies that the constructor must call the parent class’s constructor up to the proxy before assigning values to inherited properties
  3. The convenience constructor must call other constructors in the same class before assigning a value to a property
  4. The constructor cannot call any instance methods, read any instance properties, and self cannot be referenced until the first stage of construction is complete

Specifically, the two-stage process is as follows.

Phase 1
  1. One of the specified constructors or convenience constructors of the class is invoked
  2. Completes the allocation of memory for the new instance of the class, but the memory has not yet been initialized
  3. Specifies that the constructor first assigns a value to its own storage property, and the memory of the storage property completes initialization
  4. Specify that the constructor switches to the parent class constructor and performs the same task for its storage properties
  5. This process proceeds up the inheritance chain of the class until it reaches the very top of the inheritance chain
  6. When the top of the inheritance chain is reached and the last class in the inheritance chain has ensured that all stored attributes have been assigned, the memory of the instance is considered fully initialized.

Phase 1 is now complete.

The stage 2
  1. From the top of the inheritance chain down, the specified constructor for each class in the inheritance chain has the opportunity to further customize instances. The constructor can now access self, modify its properties, and invoke instance methods
  2. Finally, any convenience constructor in the inheritance chain has the opportunity to customize instances and use self

Constructor inheritance and overwriting

Unlike Objective-C, subclasses in Swift do not inherit their parent’s constructor by default. In a subclass, if you want to provide the same constructor as the parent class, you can provide a custom implementation. This is essentially a rewrite of a method in the parent class, so you need to add the Override keyword in front of it.

Note that you need to add the Override keyword even if you override the default constructor of the parent class.

Automatic inheritance of constructors

By default, subclasses do not inherit the constructor of their parent class. However, in some special cases, a subclass may inherit a constructor from its parent class.

Prerequisite: New attributes in subclasses are set to default values,

The following two rules will apply:

  1. If a subclass does not define any specified constructors, the subclass automatically inherits all specified constructors from its parent class
  2. If a subclass provides implementations of all the parent class specified constructors, the subclass automatically inherits all the parent class’s convenience constructors

Note that rule 2, when a subclass does not define any specified constructors, the subclass automatically inherits all specified constructors from its parent class. In this case, the subclass also provides implementations of all specified constructors from its parent class. Therefore:

When a subclass does not define any specified constructors, the subclass automatically inherits all specified constructors and convenience constructors from its parent class.

The override keyword

When a subclass overrides a method in its parent class, it must be qualified with the override keyword. If a subclass overrides a parent class method without using the override modifier, an error will be compiled, such as:

func layoutSubviews() {
        super.layoutSubviews()
}
Copy the code

Compile error without override modifier, error message:

Overriding declaration requires an 'override' keyword
Copy the code

If the override modifier is used but the method is not in the parent class, an error will also be compiled, such as:

override func test(){
        
}
Copy the code

Error: Test () method not found in parent class

Method does not override any method from its superclass
Copy the code

Failable constructor

Add a question mark after the constructor function to indicate a failable constructor. The following is an example:

struct Person { var name: String var age: Int init? (name: String,age: Int){ if(age < 0){ return nil } self.name = name self.age = age } }Copy the code

Note:

The parameter names and parameter types of failable constructors cannot be the same as those of other non-failable constructors. Otherwise, a compilation error will occur.

Mandatory constructor

If the required tag constructor is used in a class, it is called a required constructor. All subclasses of the class need to implement the constructor. As follows:

class TestDefault {
    var title = "test"
    var number = 1
    
    required init(title: String, number: Int){
        self.title = title
        self.number = number
    }
}

class CustomDefault: TestDefault {
    var x = 5
    
    init(x: Int){
        self.x = x
        super.init(title: "", number: 1)
    }
}
Copy the code

CustomDefault does not have a mandatory constructor, and an error message is displayed.

required' initializer 'init(title:number:)' must be provided by subclass of 'TestDefault'
Copy the code

Add the required constructor to CustomDefault:

class CustomDefault: TestDefault {
    var x = 5
    
    init(x: Int){
        self.x = x
        super.init(title: "", number: 1)
    }
    
    required init(title: String, number: Int) {
        super.init(title: title, number: number)
    }
}
Copy the code

Compilation is ok. Note that the required constructor in the subclass also needs to add the required keyword. This applies to the property on the inheritance chain.