Initialization¶Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that’s required before the new instance is ready for use. Show
You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers don’t return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they’re used for the first time. Instances of class types can also implement a deinitializer, which performs any custom cleanup just before an instance of that class is deallocated. For more information about deinitializers, see Deinitialization. Setting Initial Values for Stored Properties¶Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties can’t be left in an indeterminate state. You can set an initial value for a stored property within an initializer, or by assigning a default property value as part of the property’s definition. These actions are described in the following sections. Note When you assign a default value to a stored property, or set its initial value within an initializer, the value of that property is set directly, without calling any property observers. Initializers¶Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, written using the
The example below defines a new structure called
The structure defines a single initializer, Default Property Values¶You can set the initial value of a stored property from within an initializer, as shown above. Alternatively, specify a default property value as part of the property’s declaration. You specify a default property value by assigning an initial value to the property when it’s defined. Note If a property always takes the same initial value, provide a default value rather than setting a value within an initializer. The end result is the same, but the default value ties the property’s initialization more closely to its declaration. It makes for shorter, clearer initializers and enables you to infer the type of the property from its default value. The default value also makes it easier for you to take advantage of default initializers and initializer inheritance, as described later in this chapter. You can write the
Customizing Initialization¶You can customize the initialization process with input parameters and optional property types, or by assigning constant properties during initialization, as described in the following sections. Initialization Parameters¶You can provide initialization parameters as part of an initializer’s definition, to define the types and names of values that customize the initialization process. Initialization parameters have the same capabilities and syntax as function and method parameters. The following example defines a structure called
The first initializer has a single initialization parameter with an argument label of Parameter Names and Argument Labels¶As with function and method parameters, initialization parameters can have both a parameter name for use within the initializer’s body and an argument label for use when calling the initializer. However, initializers don’t have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic argument label for every parameter in an initializer if you don’t provide one. The following example defines a structure called
Both initializers can be used to create a new
Note that it isn’t possible to call these initializers without using argument labels. Argument labels must always be used in an initializer if they’re defined, and omitting them is a compile-time error:
Initializer Parameters Without Argument Labels¶If
you don’t want to use an argument label for an initializer parameter, write an underscore ( Here’s an expanded version of the
The initializer call Optional Property Types¶If your custom type has a stored property that’s logically allowed to have “no value”—perhaps because its value can’t
be set during initialization, or because it’s allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of The following example defines a class called
The response to a survey question can’t be known until it’s asked, and so the Assigning Constant Properties During Initialization¶You can assign a value to a constant property at any point during initialization, as long as it’s set to a definite value by the time initialization finishes. Once a constant property is assigned a value, it can’t be further modified. Note For class instances, a constant property can be modified during initialization only by the class that introduces it. It can’t be modified by a subclass. You can revise the
Default Initializers¶Swift provides a default initializer for any structure or class that provides default values for all of its properties and doesn’t provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values. This example defines a class called
Because all properties of the Memberwise Initializers for Structure Types¶Structure types automatically receive a memberwise initializer if they don’t define any of their own custom initializers. Unlike a default initializer, the structure receives a memberwise initializer even if it has stored properties that don’t have default values. The memberwise initializer is a shorthand way to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name. The example below defines a structure called The
When you call a memberwise initializer, you can omit values for any properties that have default values. In the example above, the
Initializer Delegation for Value Types¶Initializers can call other initializers to perform part of an instance’s initialization. This process, known as initializer delegation, avoids duplicating code across multiple initializers. The rules for how initializer delegation works, and for what forms of delegation are allowed, are different for value types and class types. Value types (structures and enumerations) don’t support inheritance, and so their initializer delegation process is relatively simple, because they can only delegate to another initializer that they provide themselves. Classes, however, can inherit from other classes, as described in Inheritance. This means that classes have additional responsibilities for ensuring that all stored properties they inherit are assigned a suitable value during initialization. These responsibilities are described in Class Inheritance and Initialization below. For value types, you use Note that if you define a custom initializer for a value type, you will no longer have access to the default initializer (or the memberwise initializer, if it’s a structure) for that type. This constraint prevents a situation in which additional essential setup provided in a more complex initializer is accidentally circumvented by someone using one of the automatic initializers. Note If you want your custom value type to be initializable with the default initializer and memberwise initializer, and also with your own custom initializers, write your custom initializers in an extension rather than as part of the value type’s original implementation. For more information, see Extensions. The following example defines a custom
You can initialize the
The first
The second
The third
The Note For an alternative way to write this example without defining the Class Inheritance and Initialization¶All of a class’s stored properties—including any properties the class inherits from its superclass—must be assigned an initial value during initialization. Swift defines two kinds of initializers for class types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers. Designated Initializers and Convenience 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. Classes tend to have very few designated initializers, and it’s quite common for a class to have only one. Designated initializers are “funnel” points through which initialization takes place, and through which the initialization process continues up the superclass chain. Every class must have at least one designated initializer. In some cases, this requirement is satisfied by inheriting one or more designated initializers from a superclass, as described in Automatic Initializer Inheritance below. 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. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type. You don’t have to provide convenience initializers if your class doesn’t require them. Create convenience initializers whenever a shortcut to a common initialization pattern will save time or make initialization of the class clearer in intent. Syntax for Designated and Convenience Initializers¶Designated initializers for classes are written in the same way as simple initializers for value types:
Convenience initializers
are written in the same style, but with the
Initializer Delegation for Class Types¶To simplify the relationships between designated and convenience initializers, Swift applies the following three rules for delegation calls between initializers: Rule 1A designated initializer must call a designated initializer from its immediate superclass. Rule 2A convenience initializer must call another initializer from the same class. Rule 3A convenience initializer must ultimately call a designated initializer. A simple way to remember this is:
These rules are illustrated in the figure below: Here, the superclass has a single designated initializer and two convenience initializers. One convenience initializer calls another convenience initializer, which in turn calls the single designated initializer. This satisfies rules 2 and 3 from above. The superclass doesn’t itself have a further superclass, and so rule 1 doesn’t apply. The subclass in this figure has two designated initializers and one convenience initializer. The convenience initializer must call one of the two designated initializers, because it can only call another initializer from the same class. This satisfies rules 2 and 3 from above. Both designated initializers must call the single designated initializer from the superclass, to satisfy rule 1 from above. Note These rules don’t affect how users of your classes create instances of each class. Any initializer in the diagram above can be used to create a fully initialized instance of the class they belong to. The rules only affect how you write the implementation of the class’s initializers. The figure below shows a more complex class hierarchy for four classes. It illustrates how the designated initializers in this hierarchy act as “funnel” points for class initialization, simplifying the interrelationships among classes in the chain: Two-Phase Initialization¶Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use. The use of a two-phase initialization process makes initialization safe, while still giving complete flexibility to each class in a class hierarchy. Two-phase initialization prevents property values from being accessed before they’re initialized, and prevents property values from being set to a different value by another initializer unexpectedly. Note Swift’s two-phase initialization process is similar to initialization
in Objective-C. The main difference is that during phase 1, Objective-C assigns zero or null values (such as Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error: Safety check 1A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer. As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all of its own properties are initialized before it hands off up the chain. Safety check 2A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization. Safety check 3A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn’t, the new value the convenience initializer assigns will be overwritten by its own class’s designated initializer. Safety check 4An initializer can’t call any instance methods, read the values of any instance properties, or refer to The class instance isn’t fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase. Here’s how two-phase initialization plays out, based on the four safety checks above: Phase 1
Phase 2
Here’s how phase 1 looks for an initialization call for a hypothetical subclass and superclass: In this example, initialization begins with a call to a convenience initializer on the subclass. This convenience initializer can’t yet modify any properties. It delegates across to a designated initializer from the same class. The designated initializer makes sure that all of the subclass’s properties have a value, as per safety check 1. It then calls a designated initializer on its superclass to continue the initialization up the chain. The superclass’s designated initializer makes sure that all of the superclass properties have a value. There are no further superclasses to initialize, and so no further delegation is needed. As soon as all properties of the superclass have an initial value, its memory is considered fully initialized, and phase 1 is complete. Here’s how phase 2 looks for the same initialization call: The superclass’s designated initializer now has an opportunity to customize the instance further (although it doesn’t have to). Once the superclass’s designated initializer is finished, the subclass’s designated initializer can perform additional customization (although again, it doesn’t have to). Finally, once the subclass’s designated initializer is finished, the convenience initializer that was originally called can perform additional customization. Initializer Inheritance and Overriding¶Unlike subclasses in Objective-C, Swift subclasses don’t inherit their superclass initializers by default. Swift’s approach prevents a situation in which a simple initializer from a superclass is inherited by a more specialized subclass and is used to create a new instance of the subclass that isn’t fully or correctly initialized. Note Superclass initializers are inherited in certain circumstances, but only when it’s safe and appropriate to do so. For more information, see Automatic Initializer Inheritance below. If you want a custom subclass to present one or more of the same initializers as its superclass, you can provide a custom implementation of those initializers within the subclass. When you write a subclass initializer that matches a superclass designated initializer, you are effectively providing an override of
that designated initializer. Therefore, you must write the As with an overridden property, method or subscript, the presence of the Note You always write the Conversely, if you write a subclass initializer that matches a superclass convenience initializer, that
superclass convenience initializer can never be called directly by your subclass, as per the rules described above in Initializer Delegation for Class Types. Therefore, your subclass is not (strictly speaking) providing an override of the superclass initializer. As a result, you don’t write the The example below defines a base class called
The
The next example defines a subclass of
The The If you create an instance of
If a subclass initializer performs no customization in phase 2 of the initialization process, and the superclass has a synchronous, zero-argument designated initializer, you can omit a call to This example defines another subclass of
An instance of
Note Subclasses can modify inherited variable properties during initialization, but can’t modify inherited constant properties. Automatic Initializer Inheritance¶As mentioned above, subclasses don’t inherit their superclass initializers by default. However, superclass initializers are automatically inherited if certain conditions are met. In practice, this means that you don’t need to write initializer overrides in many common scenarios, and can inherit your superclass initializers with minimal effort whenever it’s safe to do so. Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply: Rule 1If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers. If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers. These rules apply even if your subclass adds further convenience initializers. Note A subclass can implement a superclass designated initializer as a subclass convenience initializer as part of satisfying rule 2. Designated and Convenience Initializers in Action¶The following example shows designated initializers, convenience
initializers, and automatic initializer inheritance in action. This example defines a hierarchy of three classes called The base class in the hierarchy is called
The figure below shows the initializer chain for the Classes don’t have a default memberwise initializer, and so the
The The
The second class in the hierarchy is a subclass of
The figure below shows the initializer chain for the The
The Even though In this example, the superclass for All three of these initializers can be used to
create new
The third and final class in the hierarchy is a subclass of Every item in the shopping list starts out as “unpurchased”. To represent this fact,
Note
Because it provides a default value for all of the properties it introduces and doesn’t define any initializers itself, The figure below shows the overall initializer chain for all three classes: You can use all three of the inherited initializers to create a new
Here, a new array called Failable Initializers¶It’s sometimes useful to define a class, structure, or enumeration for which initialization can fail. This failure might be triggered by invalid initialization parameter values, the absence of a required external resource, or some other condition that prevents initialization from succeeding. 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 Note You can’t define a failable and a nonfailable initializer with the same parameter types and names. A failable initializer creates an optional value of the type it initializes. You write Note Strictly speaking, initializers don’t return a value. Rather, their role is to ensure that For instance, failable initializers are implemented for numeric
type conversions. To ensure conversion between numeric types maintains the value exactly, use the
The example below defines a structure called
You can use this failable initializer to try to initialize a new
If you pass an empty string value to the
failable initializer’s
Note Checking for an empty string value (such as Failable Initializers for Enumerations¶You can use a failable initializer to select an appropriate enumeration case based on one or more parameters. The initializer can then fail if the provided parameters don’t match an appropriate enumeration case. The example below defines an enumeration called
You can use this failable initializer to choose an appropriate enumeration case for the three possible states and to cause initialization to fail if the parameter doesn’t match one of these states:
Failable Initializers for Enumerations with Raw Values¶Enumerations with raw values automatically receive a failable initializer, You can rewrite the
Propagation of Initialization Failure¶A failable initializer of a class, structure, or enumeration can delegate across to another failable initializer from the same class, structure, or enumeration. Similarly, a subclass failable initializer can delegate up to a superclass failable initializer. In either case, if you delegate to another initializer that causes initialization to fail, the entire initialization process fails immediately, and no further initialization code is executed. Note A failable initializer can also delegate to a nonfailable initializer. Use this approach if you need to add a potential failure state to an existing initialization process that doesn’t otherwise fail. The example below defines a subclass of
The failable initializer for If you create a
If you try to create a
Similarly, if you try to create a
Overriding a Failable Initializer¶You can override a superclass failable initializer in a subclass, just like any other initializer. Alternatively, you can override a superclass failable initializer with a subclass nonfailable initializer. This enables you to define a subclass for which initialization can’t fail, even though initialization of the superclass is allowed to fail. Note that if you override a failable superclass initializer with a nonfailable subclass initializer, the only way to delegate up to the superclass initializer is to force-unwrap the result of the failable superclass initializer. Note You can override a failable initializer with a nonfailable initializer but not the other way around. The example below defines a class called
The next example
defines a subclass of
The You can use forced unwrapping in an initializer to call a failable initializer from the superclass as part of the
implementation of a subclass’s nonfailable initializer. For example, the
In this
case, if the The init! Failable Initializer¶You typically define a failable initializer that creates an optional instance of the appropriate type by placing a question mark after the You can delegate from Required Initializers¶Write the
You must also write the
Note You don’t have to provide an explicit implementation of a required initializer if you can satisfy the requirement with an inherited initializer. Setting a Default Property Value with a Closure or Function¶If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value. These kinds of closures or functions typically create a temporary value of the same type as the property, tailor that value to represent the desired initial state, and then return that temporary value to be used as the property’s default value. Here’s a skeleton outline of how a closure can be used to provide a default property value:
Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure. Note If you use a closure to initialize a property, remember that the rest of the instance hasn’t yet been initialized at the point that the closure is executed. This means that you can’t access any other property values from within your closure,
even if those properties have default values. You also can’t use the implicit The example below defines a structure called To represent this game board, the The
Whenever a new
Which of the following describes possible values for variables with the type Boolean?Answer: Explanation: Boolean variable can contain only one of two possible values, true and false.
How is a boolean variable declared in a program?Boolean variables are variables that can have only two possible values: true, and false. To declare a Boolean variable, we use the keyword bool. To initialize or assign a true or false value to a Boolean variable, we use the keywords true and false.
Which of the following is a proper way to declare and initialize a variable in Java?To declare (create) a variable, you will specify the type, leave at least one space, then the name for the variable and end the line with a semicolon ( ; ). Java uses the keyword int for integer, double for a floating point number (a double precision number), and boolean for a Boolean value (true or false).
How many Boolean values are there quizlet?Boolean values can hold one of two values, true or false.
|