Optional
In Swift 5.8 programs, a func
may sometimes fail and have no valid value (like an Int
) to return. This method can return an optional Int
, not an Int
.
When a func
has no value to return, we do not need to know a special "failure" code. Instead we test the returned optional value. We see if any value exists.
This program shows a func
that returns an optional String
. This is specified as a "String
?" return value. The func
returns a String
or nil
.
computeName()
method and tests the optional String
in an if
-statement.nil
.func computeName(id: Int) -> String? { // This returns an optional string. switch id { case 0: return "Car" case 1: return "Fish" case 2: return "House" default: return nil } } // Get optional string from this func. let name1 = computeName(id: 1) // See if optional string is not nil. if name1 != nil { // Use exclamation point to get string from optional. let value = name1! print(value) }Fish
Optional
bindingThis feature lets us assign a name to an optional in an if
-statement. Inside the if
-block, we can access the value (like a String
) with no special syntax.
String
value, not an optional. So we directly use it.func computeId(id: Int) -> String? { // Return an optional string. if id == 0 { return nil } else { return "1" } } if let id = computeId(id: 10) { // Use id as a string, not an optional string. // ... No exclamation point is needed. print(id) } if let id = computeId(id: 0) { // This is not reached. print(false) }1
A class
can have an optional field. No special init
method is required to initialize an optional field. These fields begin as nil
values.
String
. It begins life as nil
, but we change it to "Blue" and then test its value.class Box { var color: String? } // Create Box instance. var box = Box() // Optional is nil. if let c = box.color { print(0) } // Assign optional to String value. box.color = "Blue" // Use "if let" statement. if let c = box.color { print("Box has color \(c)") // The optional can be accessed with an exclamation mark. print(box.color!) }Box has color Blue Blue
With optional chaining, we can safely access nested optionals. If an early access is nil
, further accesses will not be done. The end result is nil
unless a valid result is found.
class
contains an optional Side class
instance. It requires no init
method because its only field is optional.class
has an optional pixels Int
. We can access a Side's pixels through a special expression.class Box { var side: Side? } class Side { var pixels: Int? } // Create instance of class. var example = Box() // Access a field on a nil optional. let pixels = example.side?.pixels print(pixels) // Does not exist. // Initialize the optional field. example.side = Side() // Assign field on the instance. example.side!.pixels = 10 // Access field through nested optionals. print(example.side!.pixels!)nil 10
A subscript (like the lookup method of a dictionary) can return an optional value. Here we use optional syntax to increment and decrement values in a dictionary.
var colors = ["Blue": 140, "Red": 30] // Increment and decrement optional values. colors["Blue"]? += 1 colors["Red"]? -= 1 // This has no effect. colors["Hello"]? += 1 // Display dictionary. print(colors)["Blue": 141, "Red": 29]
With the "try!" and "try?" syntax, we can convert an error thrown by a method into an optional. This makes calling exception-throwing funcs easier.
With optionals, Swift makes failure values consistent. It means we have a unified, reliable way to test for "no value." This makes programs clearer.