In Swift, types like classes and structs have init
methods. The init()
method sets up all the initial values of the type instance.
With multiple init
methods, and convenience init
methods, we set up values in an efficient way. And failable init
let us exit the init
method early if the arguments are invalid.
This example shows a designated initializer, which uses the init
keyword, and a convenience initializer, which has the "convenience" keyword.
init
method. This receives any number of parameters and uses the arguments received to set up the fields within the class
.init
method calls into the self.init()
method. It can make a class
easier to create by specifying fewer arguments.init
method, we specify the type name with the arguments to init()
. The init
method is then executed.init
method can also be accessed by specifying the type name, with the appropriate arguments.class Bird { var color = "" var feathers = 0 // Part 1: designated initializer in class. init(c: String, f: Int) { self.color = c self.feathers = f } // Part 2: convenience initializer, which calls the designated initializer. convenience init(c: String) { self.init(c: c, f: 100) } } // Part 3: use designated initializer. var b = Bird(c: "blue", f: 200) print("Bird: \(b.color) \(b.feathers)") // Part 4: use convenience initializer. var b2 = Bird(c: "red") print("Bird: \(b2.color) \(b2.feathers)")Bird: blue 200 Bird: red 100
init
Sometimes a class
can benefit from multiple separate init
methods. It is sometimes possible to use a convenience init
in this case, but not necessary.
class Example { var size1 = 0 var size2 = 0 // An initializer. init(size1: Int, size2: Int) { self.size1 = size1 self.size2 = size2 } // Another initializer. init(allSizes: Int) { self.size1 = allSizes self.size2 = allSizes } } // Use the first initializer method. var e = Example(size1: 10, size2: 20) print("Example \(e.size1) \(e.size2)") // Use the second initializer. var e2 = Example(allSizes: 30) print("Example \(e2.size1) \(e2.size2)")Example 10 20 Example 30 30
Suppose we want to create a class
or struct
but only if the arguments to the init()
method are valid. Otherwise, we want to return a nil
value.
init
. We use a question mark after the "init
" keyword for this purpose.init
method, but it returns an optional value.if-let
statement.struct Test { var id = 0 // Part 1: use failable initializer to avoid structs with id of 0. init?(id: Int) { if id == 0 { return nil } self.id = id } } // Part 2: use failable initializer. let t = Test(id: 20)! print("Test \(t.id)") // Part 3: get nil struct from failable initializer. let t2 = Test(id: 0) if t2 == nil { print("Nil Test optional") }Test 20 Nil Test optional
Init methods in classes and structs help us create objects in a consistent way. This keeps the quality of our programs higher and makes programs easier to read.