The Rect class described earlier demonstrated initialization by
assignment in the class definition:
class Rect
{
var x = 0.0, y = 0.0
var width = 0.0, height = 0.0
// rest of definition }
This can be rewritten to use a designated initializer function instead, like this:
class Rect
{
var x, y, width, height: Double
init() {
x = 0.0; y = 0.0
width = 0.0; height = 0.0
}
// remainder of class definition }
This default init() function, without parameters, is the initial‐
izer that is called when you create a new object with no initiali‐ zation parameters, as in the following:
var q = Rect()
You can create additional initializers, each of which takes dif‐ ferent numbers and/or types of parameters. The following extended version of the Rect class includes two different desig‐
nated initializer methods, either of which will be called depending on how the Rect is instantiated:
class Rect6
{
var x, y, width, height: Double
init() {
x = 0.0; y = 0.0
width = 0.0; height = 0.0
}
init(x: Double, y: Double, width: Double, height: Double) {
self.x = x
self.y = y
self.width = width
self.height = height
} }
Now, either init() method can be used to construct Rect
instances:
var rectI1 = Rect6()
var rectI2 = Rect6(x: 2.0, y: 2.0, width: 5.0, height: 5.0)
Note that the second init() function has only defined local
parameter names, but the instantiation of rectI2 shows they
are externally visible.
NOTE
For init() functions, Swift will always generate an exter‐ nal parameter name if one hasn’t been defined. Moreover, external parameter names (whether explicitly defined or implicitly generated) must be used when the class is instantiated.
If you want to prevent the generation of an external parameter name, precede the local parameter name with an underscore, like this:
class Rect6
{
var x, y, width, height: Double
init() {
x = 0.0; y = 0.0
width = 0.0; height = 0.0
}
init(_ x: Double, _ y: Double, _ width: Double, _ height: Double) {
self.x = x
self.y = y
self.width = width
self.height = height
} }
Because there are now no external parameter names, new instances of the class can be created just by specifying the parameter values, as shown here:
var rectI3 = Rect6(2.0, 2.0, 5.0, 5.0)
Convenience initializers
Convenience initializers are secondary initialization functions that must call some other initializer within the same class, and ultimately they must cause the execution of a designated initializer.
In “Defining a Base Class” on page 108, a simple class called
Processor was introduced to represent microprocessors. The
use of this class might require frequent instantiation of a partic‐ ular type of processor, and hence warrant the inclusion of a convenience initializer: class Processor2 { var dataWidth = 0 var addressWidth = 0 var registers = 0 var name = ""
init (name: String, dWidth: Int, aWidth: Int, regs: Int) {
self.name = name
dataWidth = dWidth
addressWidth = aWidth
registers = regs
}
convenience init (eightbitName: String, regs: Int) {
self.init(name: eightbitName, dWidth:8, aWidth:16, regs: regs) }
}
Note that the convenience initializer defaults two of the four parameters required by the designated initializer, which it calls as self.init().
The convenience initializer is called automatically when a new instance is created with parameters that match its signature, as in the following example:
var p = Processor2(eightbitName:"6502", regs:3)
Failable initializers
A failable initializer is one that can return nil if a class, struc‐
ture, or enumeration is unable to properly initialize an instance of itself. For example, a class might require that a resource be available on disk, or a network connection be available, before it can be instantiated.
You indicate that an initializer is failable by defining it as init?().
Following is a version of the Employee class that includes a fail‐
able initializer. The initialization will fail if the family name concatenated with the given name is an empty string:
class Employee3
{
static var nextID = 1
var familyName: String
var givenName: String
var employeeID = 0
init?(familyName: String, givenName: String) {
self.familyName = familyName
self.givenName = givenName
if familyName + givenName == "" { return nil
}
employeeID = Employee3.nextID++ }
}
When instances of this class are created using this specific ini‐ tializer, they are optionals. Consider the following code:
var emp1 = Employee3(familyName: "Jones", givenName: "Bob") var emp2 = Employee3(familyName: "", givenName: "")
emp1?.givenName // returns "Bob"
emp2?.givenName // returns nil
Both emp1 and emp2 are of type Employee3?—optional values
that must be unwrapped in order to access the employee record. emp1 contains a valid employee record, whereas emp2
is nil.
Some other points to note include:
• For classes, a failable initializer must not fail (return nil)
until after all stored properties for the class have been set to an initial value, and a designated initializer has been run.
• A failable initializer can call another failable initializer in the same class or a superclass. If that initializer fails, the entire initialization process fails immediately.
• A failable initializer can be overridden in a subclass with either a failable or a nonfailable initializer.
• A failable initializer cannot override a nonfailable initial‐ izer in a superclass.
• You can create an implicitly unwrapped failable initializer by defining it as init!(). If you do so, you must check
methods and properties, otherwise a runtime error will occur.