🎓 A1Learner
🔍
0 of 36 lessons completed

Swift Initializers in Depth

An initializer sets up a new object before it is used. A class can add helper initializers that delegate to the main one, and an initializer can fail and give back no object.

A convenience initializer delegates

The Cup class has a designated initializer that takes a name and a size. The convenience initializer supplies a size of 12 and delegates with self.init.

class Cup {
    var name: String
    var size: Int
    init(name: String, size: Int) {
        self.name = name
        self.size = size
    }
    convenience init(name: String) {
        self.init(name: name, size: 12)
    }
}
let big = Cup(name: "Mug", size: 20)
let plain = Cup(name: "Cup")
print(big.name)
print(big.size)
print(plain.name)
print(plain.size)

A failable initializer returns nil

The Bottle initializer fails when the size is not positive. The first call succeeds, and the second call takes the else branch.

class Bottle {
    var size: Int
    init?(size: Int) {
        if size <= 0 {
            return nil
        }
        self.size = size
    }
}
if let bottle = Bottle(size: 500) {
    print(bottle.size)
} else {
    print("No bottle")
}
if let empty = Bottle(size: 0) {
    print(empty.size)
} else {
    print("No bottle")
}

A subclass convenience initializer

LabeledBottle adds a label property and its own designated initializer. Its convenience initializer supplies a size of 500 and delegates to that designated initializer.

class Bottle {
    var size: Int
    init(size: Int) {
        self.size = size
    }
}
class LabeledBottle: Bottle {
    var label: String
    init(label: String, size: Int) {
        self.label = label
        super.init(size: size)
    }
    convenience init(label: String) {
        self.init(label: label, size: 500)
    }
}
let bottle = LabeledBottle(label: "Water")
print(bottle.label)
print(bottle.size)

Example

class Reading {
    var value: Int
    init?(value: Int) {
        if value < -273 {
            return nil
        }
        self.value = value
    }
}
if let reading = Reading(value: -300) {
    print(reading.value)
} else {
    print("Too cold to exist")
}
if let ok = Reading(value: 20) {
    print(ok.value)
} else {
    print("Too cold to exist")
}

Key points

  • A designated initializer gives a value to every stored property of its class.
  • A convenience initializer is a helper marked with the word convenience.
  • A convenience initializer delegates with self.init instead of setting properties itself.
  • A failable initializer is written as init? and can return nil.
  • Returning nil from a failable initializer means no object was made.
  • Code that calls a failable initializer tests the result before using it.

In this example, the Reading class has a failable initializer that returns nil for a value below -273. The value -300 takes the else branch and prints the failure line. The value 20 succeeds, so the second check prints 20.

Note

Every convenience initializer chain ends at a designated initializer.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A bottle is made with Bottle(size: 0), and its failable initializer returns nil for a size that is not positive. What does the caller receive?