Optionals
Open the Lesson01-Review-Basics playground. Start on the Lesson01-optionals page.
Failable Initializers
Some Swift standard types have initializers that can fail, so their return type is an optional. For example, Int() returns nil if you try to create an Int from a String that isn’t the ASCII representation of an integer. Run these two lines of code:
let value = Int("3") // 3
let failedValue = Int("nope") // nil
The second line is nil because “nope” doesn’t represent an integer.
When you define a raw-representable enumeration type, the compiler creates a failable initializer for it. Run the following code:
enum PetFood: String {
case kibble, canned
}
let morning = PetFood(rawValue: "kibble") // .kibble
let snack = PetFood(rawValue: "fuuud!") // nil
The raw value “fuuud!” isn’t one of the PetFood cases, so snack is nil.
In struct PetHouse, write your own failable initializer — add this code:
init?(squareFeetAsString: String) { // 1
guard let squareFeet = Int(squareFeetAsString) else { // 2
return nil
}
self.squareFeet = squareFeet
}
-
init?indicates this initializer can returnnil - If
Int()returnsnil, thisinitfails too.
Now, to test this init, uncomment then run these lines of code:
let house = PetHouse(squareFeetAsString: "100") // PetHouse?
let nopeHouse = PetHouse(squareFeetAsString: "nope") // nil
Again, “nope” isn’t an integer, so PetHouse(squareFeetAsString: "nope") returns nil.
Optional Chaining
Many people own pets — but not all. Some pets have a favorite toy, and others don’t. Some of these toys make noise, and others don’t. Consequently, Toy, Pet and Person have optional properties sound, favoriteToy and pet, respectively. Run the following code to create three Person objects:
let janie = Person(pet: Pet(name: "Delia", kind: .dog, favoriteToy: Toy(kind: .ball, color: "Purple", sound: .bell)))
let tammy = Person(pet: Pet(name: "Evil Cat Overlord", kind: .cat, favoriteToy: Toy(kind: .mouse, color: "Orange")))
let felipe = Person()
Two Person objects have pets who have a favorite toy, but only Janie’s pet’s toy has a sound. Felipe doesn’t have a pet.
Add the following code to print the sound of the favoriteToy of the pet of each Person:
if let sound = janie.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
if let sound = tammy.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
if let sound = felipe.pet?.favoriteToy?.sound {
print("Sound \(sound).")
} else {
print("No sound.")
}
Because sound, favoriteToy and pet are all optionals, you quickly walk through these nested optionals with optional chaining — adding ? after every property or method that can return nil. If any of the chain’s values is nil, the result of the whole chain is nil. Instead of having to test every optional along the chain, you simply test the result!
Run the code:
As you expect, only Janie’s pet’s favorite toy has a sound.
Continue to the next page to review throw-catch.