The construction process of Swift's class, struct, enumeration, etc. initialization (bottom)

Source: Internet
Author: User

Class inheritance and construction procedures

All of the stored properties in the class--containing all the attributes inherited from the parent class--must be set during the construction process for the initial value.

Swift provides two types of class constructors to ensure that the stored-type properties in all class instances get their initial values, each of which is a specified constructor and a convenience constructor.

Specifying constructors and convenience constructors

Specifies that the constructor is the most basic constructor in the class. A specified constructor initializes all the properties provided in the class, and initializes the parent class by invoking the constructor of the parent class on the parent class chain.

Each class must have at least one specified constructor. In some cases, many classes satisfy this condition by inheriting the specified constructor in the parent class. For more information, please refer to the inheritance of your own active constructor.

A convenience constructor is a minor, auxiliary constructor in a class. You can define a convenience constructor to invoke the specified constructor in the same class and provide default values for its parameters. You can also define a convenience constructor to create an instance of a special purpose or specific input.

You should provide a convenient constructor for the class only when necessary, for example, by using a convenient constructor to quickly invoke a specified constructor in some cases, you can save a lot of other development time and make the class construction process clearer and more clear.

Constructor chain

To simplify the invocation relationship between the specified constructor and the convenience constructor, Swift uses the following three rules to restrict proxy calls between constructors:

Rule 1

Specifies that the constructor must call the specified constructor of its immediate parent class.

Rule 2

The convenience constructor must call other constructors defined in the same class.

Rule 3

The convenience constructor must finally end with a call to a specified constructor.

A more convenient way to remember is to:

Specifies that the constructor must always be up-agent

The convenience builder must always be a horizontal proxy

These rules can be illustrated by an example:

As you can see, the parent class includes a specified constructor and two convenience constructors. One of the convenience constructors calls another convenient constructor, and the latter invokes the only specified constructor. This satisfies the above mentioned rules 2 and 3. This parent class does not have its own parent class, so rule 1 is not practical.

The subclass includes two specified constructors and a convenience constructor. The convenience constructor must invoke the random one in the two specified constructor, since it can only invoke other constructors in the same class. This satisfies the above mentioned rules 2 and 3. The two specified constructors must call the only specified constructor in the parent class, which satisfies rule 1.

Attention:

These rules do not affect how you use classes to create instances when used. The constructors shown in any of these can be used to create an instance of the corresponding class in its entirety. These rules are only affected when implementing the definition of a class.

A more complex class hierarchy is shown in the example. It demonstrates that the specified constructor is supposed to act as a "pipe" in the class hierarchy, simplifying the internal relationship between classes on the class's constructor chain.

Two-stage construction process

The construction process for classes in Swift consists of two stages. In the first stage, each stored-type property sets the initial value by introducing the constructor of their class. When each stored-type attribute value is determined, the second phase starts, giving each class a chance to further customize their storage properties before the new instance is ready to be used.

The use of the two-stage construction process makes the construction process more secure, giving each class full flexibility at the same time throughout the class hierarchy. The two-stage construction process prevents property values from being interviewed before initialization, and prevents attributes from being accidentally assigned different values by another constructor.

Attention:

Swift's two-segment construction process is similar to the construction process in objective-c. The basic difference is that stage 1,objective-c assigns 0 or null values to each property (say, 0 or nil). Swift's construction process is more flexible, and it agrees that you can set a custom initial value and be comfortable with the case that certain properties cannot be 0 or nil as legal defaults.

The Swift compiler will run 4 effective security checks to ensure a smooth completion of the two-stage construction process:

Security 1

Specifies that the constructor must ensure that all properties introduced by its class must be initialized before it can delegate other construction tasks up to the constructor in the parent class.

As mentioned above, the memory of an object only has the ability to fully initialize after all of its stored-type properties have been determined. To satisfy this rule, the specified constructor must ensure that the property introduced by its class is initialized before it can be proxied.

Security 2

Specifies that the constructor must first call the parent class constructor on the proxy, and then set the new value for the inherited property. Assuming this is not done, the new value given by the specified constructor is overwritten by the constructor in the parent class.

Security 3

The convenience constructor must first invoke the other constructors in the same class, and then assign a new value to the discretionary property. Assuming this is not done, the new value given by the convenience constructor is overwritten by the other specified constructors in the same class.

Security 4

The constructor cannot invoke any instance method, cannot read the value of any instance property, or reference the value of self until the first stage is constructed.

The following is a demonstration of the construction process based on the above security checks during the two-stage construction process:

Stage 1

A specified constructor or convenience constructor is called;

Complete the allocation of the new instance memory, but the memory is not initialized at this time;

Specifies that the constructor ensures that all stored-type properties introduced by the class are assigned an initial value. The memory that the storage attribute belongs to is initialized;

Specifies that the constructor will invoke the constructor of the parent class, completing the initialization of the parent class property;

The process of invoking the parent class constructor runs upward along the chain of the constructor until it reaches the top of the constructor chain;

When the top of the constructor chain has been reached and the stored properties of all instances are guaranteed to have been assigned, the memory of the instance is felt to be fully initialized. Phase 1 is complete at this point.

Stage 2

From the top of the constructor chain down, the specified constructors for classes in each constructor chain have the opportunity to further customize the instance. The constructor can now access the self, change its properties, invoke the instance method, and so on.

Finally, the convenience constructors in the random constructor chain can have the opportunity to customize the instance and use self.


In this example, the construction process begins with a call to a convenient constructor in a subclass. This handy constructor cannot be changed at this time. Regardless of the properties, it proxies the construction task to the specified constructor in the same class.

As seen in security check 1, specifying the constructor will ensure that all child classes have values for their properties. It then invokes the specified constructor of the parent class and, along the builder chain, completes the parent class's build process.

The specified constructor in the parent class ensures that all properties of the parent class have values. Because there are not many other parent classes that need to be built, there is no need to continue building the proxy up.

Once all the attributes in the parent class have an initial value, the memory of the instance is thought to be fully initialized, and Phase 1 is complete.


The specified constructor in the parent class now has the opportunity to further customize the instance (although it is not necessary).

Once the specified constructor in the parent class has been called, the constructor of the subclass specifies that the constructors can run many other custom operations (the same, it is not necessary).

Finally, once the specified constructor of the subclass has been called, the convenience constructor that is called the most is able to run many other custom operations.

Inheritance and overloading of constructors

Unlike subclasses in Objective-c, child classes in Swift do not inherit the constructor of the parent class by default. This mechanism of Swift prevents a simple constructor of a parent class from being inherited by a more specialized subclass and is incorrectly used to create instances of subclasses.

Suppose you want to implement one or more constructors that are the same as the parent class in the subclass you are defining-perhaps to complete some custom constructs-you can provide and reload the same constructor as the parent class in your custom subclass.

Suppose that your overloaded constructor is a specified constructor, you can overload its implementation in a subclass, and call the constructor of the parent class version number in the constructor that defines the version number.

Suppose your overloaded constructor is a convenience constructor, your overloaded procedure must be implemented by invoking the other specified constructors provided in the same class. Please refer to the constructor chain for the specific contents of this rule.

Attention:

Unlike methods, properties, and subscripts, you do not need to use keywordoverride when overloading the constructor.

Inherit from your own active constructor

As mentioned above, subclasses do not inherit the constructor of the parent class by default. But assuming that certain conditions are met, the parent constructor can be inherited by itself. In practice, this means that you do not have to reload the constructor of the parent class for many common scenarios, and inherit the constructor of the parent class at the lowest cost possible.

If you want to provide default values for random new properties introduced in subclasses, follow these 2 rules:

Rule 1

Assuming that the subclass is undefined, no matter what the specified constructor, it will itself inherit the specified constructor of all the parent classes.

Rule 2

Suppose the subclass provides all the parent class to specify the implementation of the constructor-either inherited through Rule 1 or implemented by its own definition-that inherits the convenience constructor of all the parent classes itself.

Even if you add a lot of other handy constructors to the subclass, these two rules still apply.

Attention:

Subclasses can implement a specified constructor of a parent class by using a subclass convenience constructor, partially satisfying rule 2.

Syntax for specifying constructors and convenience constructors

The specified constructor for a class is the same as the value type simple constructor:

Init (parameters) {   statements}


The convenience constructors also use the same notation, but need to place Conveniencekeyword before Initkeyword and separate them with spaces:

Convenience init (Parameters) {   statements}


Specifying constructors and convenient constructors for real combat

The following example shows the inheritance of the specified constructor, the convenience builder, and its own active constructor in the actual combat. It defines class hierarchies that include three classes of food, recipeingredient, and Shoppinglistitem, and shows how their constructors interact.

The base class in the class hierarchy is food, which is a simple class used to encapsulate the names of foods. The food class introduces a String type property called Name, and provides two constructors to create food instances:

Class Food {   var name:string   init (name:string) {       self.name = name    }   convenience init () {       Self.init (Name: "[Unnamed]")    }}



Class does not provide a default one-to-member constructor, the food class provides a specified constructor that accepts a single-parameter name. The constructor can use a specific name to create a new food instance:

Let namedmeat = food (name: "Bacon")//Namedmeat's name is "Bacon"


The constructor init (name:string) in the food class is defined as a specified constructor, because it ensures that all new food instances are initialized with the store-type attribute. The food class has no parent class, so the Init (name:string) constructor does not need to call Super.init () to complete the construction.

The food class provides a convenient constructor init () with no parameters. This init () constructor provides a default placeholder name for the new food, which is implemented by invoking the specified constructor init (name:string) defined in the same class and assigning the parameter name value [Unnamed]:

Let mysterymeat = food ()//Mysterymeat's name is [Unnamed]


The second class in the class hierarchy is the subclass of food recipeingredient. The Recipeingredient class builds a seasoning in recipes. It introduces the quantity attribute quantity of type int (and the name attribute inherited from food), and defines two constructors to create the Recipeingredient instance:

Class Recipeingredient:food {   var quantity:int   init (name:string, quantity:int) {       self.quantity = Quantity       super.init (name:name)    }   Convenience init (name:string) {       self.init (name:name, quantity:1)    }

The Recipeingredient class has a specified constructor, init (name:string, Quantity:int), which can be used to produce all the property values of a new recipeingredient instance. The constructor starts by assigning the passed-in quantity to the Quantity property, which is also the only newly introduced property in Recipeingredient. The constructor then proxies the task up to the parent food's init (name:string). This process satisfies the safety check in the two-stage construction process 1.

Recipeingredient also defines a convenience constructor, Init (name:string), that simply creates an instance of Recipeingredient by name. This handy constructor if the quantity of the Recipeingredient instance is 1, you can create an instance without displaying the specified number. The definition of this handy constructor makes it easier and faster to create instances, and avoids the use of repeated code to create multiple recipeingredient instances of quantity 1. This handy constructor is simply a simple task delegate to the specified constructor provided in the same class.

Note that Recipeingredient's convenient constructor init (name:string) uses the same parameters as the specified constructor init (name:string) in food. Although the Recipeingredient constructor is a convenience constructor, Recipeingredient still provides the implementation of specifying a constructor for all the parent classes. As a result, recipeingredient can also inherit the convenience constructors of all the parent classes on its own initiative.

In this example, the parent class of recipeingredient is food, which has a convenience constructor, Init (). This constructor is therefore also inherited by Recipeingredient. The inherited init () function version number is the same as the version number provided by food, except that it is an init (name:string) that delegates the task to the Recipeingredient version number instead of the version number provided by food.

All of these three constructors can be used to create a new Recipeingredient instance:

Let Onemysteryitem = Recipeingredient () Let Onebacon = recipeingredient (name: "Bacon") Let Sixeggs = recipeingredient (name : "Eggs", Quantity:6)


The third and last class in the class hierarchy is the subclass of Recipeingredient, called Shoppinglistitem. This class builds one of the seasonings that appear in the shopping list.

Each item in the shopping list is always started from the unpurchased status. To demonstrate this fact, Shoppinglistitem introduced a Boolean-type property, purchased, whose default value is False. Shoppinglistitem also joined? A computed attribute, description, provides some textual descriptions of Shoppinglistitem instances:

Class Shoppinglistitem:recipeingredient {   var purchased = False   var description:string {   var output = "\ (qua ntity) x \ (name.lowercasestring) "       output + = purchased? " ?" :" ?"       return output    }}


Attention:

Shoppinglistitem does not define a constructor to provide initialization values for purchased, because no matter what joins? The initial state of the item to the shopping order is always not purchased.

Because it provides default values for all of the properties that it introduces itself, and does not define itself, no matter what constructor, Shoppinglistitem itself inherits the specified constructors and convenience constructors from all the parent classes.


You can create a new instance of Shoppinglistitem using all three inherited constructors:

var breakfastlist = [   shoppinglistitem (),   Shoppinglistitem (name: "Bacon"),   Shoppinglistitem (name: "Eggs ", quantity:6),]breakfastlist[0].name =" Orangejuice "breakfastlist[0].purchased = truefor item in BreakfastList {   println (item.description)}//1 x Orange juice?//1 x Bacon?//6 x eggs?


As mentioned above, a new array breakfastlist is created by literal means in the sample, which includes three new Shoppinglistitem instances, so the type of the array can be deduced as shoppinglistitem[] on its own initiative. After the array is created, the name of the first Shoppinglistitem instance in the array is changed from [Unnamed] to orange juice and marked as purchased. Next, by iterating through each element of the array and printing their descriptive narrative values, it shows that the current default state of all items has been assigned according to the expected completion.

Setting default values for properties by closures and functions

Assuming that the default value of a stored-type property requires special customization or preparation, you can use closures or global functions to provide custom default values for their properties. Whenever an instance of a new type to which a property belongs is created, the corresponding closure or function is called, and their return value is assigned to the property as a default value.

A closure or function of such a type typically creates a temporary variable that is the same as the property type, then changes its value to meet the expected initial state, and finally returns the value of the transient variable as the default value of the property.

The following is a summary of how closures provide default values:

Class SomeClass {   let Someproperty:sometype = {       //Create a default value for Someproperty in this closure//       somevalue must be the same as the SomeType type Sample       return Somevalue       } ()}


Note that the closing curly braces are followed by a pair of empty parentheses. This is used to tell Swift that it needs to run the closure immediately. Suppose you omit this pair of parentheses, which is equivalent to assigning the closure itself as a value to the property, rather than assigning the return value of the closure to the property.

Attention:

Suppose you use closures to initialize the value of a property, keep in mind that other parts of the instance are not initialized when the closure is run. This means that you cannot access other properties in a closure, even if the property has a default value. , you cannot use the implicit Self property, or call other instance methods.

The following example defines a structural body checkerboard, which builds the chessboard of a checkers game:

The Checkers game is played in an alternating 10x10 of black and white. To present this game board, the checkerboard struct defines an attribute boardcolors, which is an array of 100 Boolean values. An element in the array with a Boolean value of TRUE indicates that the corresponding is a black lattice, and a Boolean value of False indicates that the corresponding is a white lattice. The first element in the array represents the upper-left corner of the checkerboard, and the last element represents the grid on the lower-right corner of the board.

The Boardcolor array initializes and assembles the color values through a closure:

struct Checkerboard {let   boardcolors:bool[] = {       var temporaryboard = bool[] ()       var isblack = False for       I In 1...10 {to           J in 1...10 {                temporaryboard.append (isblack)                isblack =!isblack           }           isblack =!isblack       }       Return Temporaryboard       } ()   func squareisblackatrow (Row:int, column:int), Bool {       return boardcolors [(Row *) + column]    }}


Whenever a new checkerboard instance is created, the corresponding assignment closure runs, and a series of color values are computed as default values assigned to Boardcolors. The closure described in the example above calculates the appropriate color for each lattice in the checkerboard, saves the color values to a temporary array temporaryboard, and returns the array as a closure return value when it is built. The returned value is saved to boardcolors and can be queried by squareisblackatrow the tool function.

Let board = Checkerboard () println (Board.squareisblackatrow (0, Column:1))//Output "true" println (Board.squareisblackatrow (9, Column:9)) Output "false"


The construction process of Swift's class, struct, enumeration, etc. initialization (bottom)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.