There are two methods of initializing objects in Swift: Designated Initializers and Convenience Initializers. Write down my initial understanding of it.

Swift tectonic process

It’s basically the init initialization method of OC. OC typically initializes a class (for example Person, with attributes such as name and age) using methods that begin with init as follows:

Declaration methods are exposed in.h. / / the default name ="",age=0 - (instancetype)init; // initialize with name, default age=0 - (instancetype)initWithName:(NSString *)name; // assign name and age to initialize - (instancetype)initWithName:(NSString *)name age:(NSInteger)age;Copy the code

The implementation method is as follows:

Write the method implementation in dot m. // Convenience constructor - (instanceType)init {return [self initWithName:@""]; } // convenience constructor - (instancetype)initWithName:(NSString *)name {return[self initWithName:name age:0]; } // specify constructor - (instancetype)initWithName:(NSString *)name age:(NSInteger)age {self = [super init];if(! self) {return nil;
    }
    _name = name;
    _age = age;
    return self;
}
Copy the code

The same is true for the three types of Swif, init(). Here I am

Here, I give initial values for name and age. var name: String =""Var age: Int = 0init() {
    self.init(name: "haha")// The default name is haha to indicate that a subclass can inherit the convenience init method. Init (name: name, age:0)} // Specify the constructor init(name: String, age:0). Int) { super.init() self.name = name self.age = age }Copy the code

When writing the Swift code, there are the following problems

  1. If the storage properties name and age are not initialized, an error is reported and they need to be assigned before calling the super.init() constructor of the superclass.
  2. The Designated Initializer cannot be called self.init if the Designated initializer is not configured by the Xcode option. “Convenience Initializer” is the correct choice. And then we hit fix, init and it automatically inserts convenience. Why you need to call convenience is explained later.

Note: Swift, unlike OC init, does not return a value. This process initializes all storage properties and other necessary initialization operations.

Initialize the storage properties

Store properties. Before calling any method (such as a subclass calling super.init of its parent class, or a method of its own class), you should ensure that the store properties are initialized in this class. If name and age are not given initial values, the code should look like this: init(name: String, age: Int)

init(name: String, age: Int) {
    self.name = name
    self.age = age

    super.init()
}
Copy the code

This is due to Swift’s memory safety, which ensures that all storage properties of this class are initialized before calling the parent constructor. A two-phase Initialization model is used to achieve memory security.

  1. Initialize all storage properties.
  2. It gives each class an opportunity to further customize their stored properties before new instances are ready to use them.

The Github source documentation has a three-section construction, and the third paragraph: if there are other operations, you can perform other methods to complete the initialization.

Designated Initializers

Specify constructor, which is the primary method of a class. If there is a parent class, the specified constructor method of a subclass must call the parent class’s specified constructor associated with the parent class. For example, the Swift Person class above,

  1. The constructor method specified is the last one in which name and age are both passed arguments to initialize the instance. So WHAT I understand is the basic init function, the function that other init functions need to call.
  2. The constructor method specified can only call super.init (if there is a parent class), not self.init (flat init function).
  3. The specified constructor does not have to be a single constructor. For example, the above function generates an instance from name. If the specified constructor is also written, the code is as follows:
init(name: String) {
    super.init()
    self.name = name
}
Copy the code
  1. Cannot be written in the extension extension. If there are other methods that need to be called during initialization, you need to add them here as well. Init (name: String, age: Int); copy all the code in init(name: String, age: Int).

Convenience Initializers

The convenience constructor, a convenient way to generate instances, selects the parameters of the specified constructor instead of passing so many parameters.

  1. The specified constructor of a parent class (if any) cannot be called; only self.init(the flat init function) can be called. And you must always end up with the specified constructor. This is the main reason why the opening code must use a convenience approach.
  2. Unlike the specified constructor, it can be written in the Extension extension.
  3. You can’t access self, or anything that depends on self, until you call self.init.
  4. Can be inherited by subclasses. However, subclasses must override all specified constructors of their parent class. Using the Person class above as an example, I created a subclass Boy that inherits from Person. If you want to use the boy.init () method, then the Boy class should override all the specified constructors of the Person class. The code is as follows:
class Boy: Person {
    
    var girlFriendName: String
    
    override init(name: String, age: Int) {
        self.girlFriendName = "girl"
        super.init(name: name, age: age)
        print("I'm done init.")}}Copy the code

If there is another specified constructor in Person, the Boy class needs to override that method as well. Otherwise calling boy.init () returns an error. The call to boy.init () is constructed as follows:

  1. Memory allocation for the Boy object, but not initialized at this time.
  2. Boy.init() calls the convenience init method inherited from its parent class.
  3. The convenience init(Name: String) method of Person is then called based on the code.
  4. Call back to the init(name: String, age: Int) method of Boy’s overwritten superclass.
  5. Finish initializing all storage properties of the Boy class.
  6. Call the designated constructor of the parent class Person (then complete the initialization of all stored attributes of the Person class and call the designated constructor of the parent class of Person. Initializing all storage properties up the class inheritance chain.
  7. Call a reassignment of Person (or directly if there are other initial initializations). Then call Boy’s print method. That is, after the first phase is complete, the second phase, which can reassign the storage property or call other methods to initialize it, will be executed from the top of the class inheritance chain), and then return.
  8. The traversal method of Person returns.