Optionals

Last updated on 18 Oct 2024.

Written by Jia Chen.

Swift Playgrounds for iPad app icon

Sample Project

Optionals

Last updated on 18 Oct 2024.

Written by Jia Chen.

Swift Playgrounds for iPad app icon

Sample Project

Optionals

Last updated on 18 Oct 2024.

Written by Jia Chen.

Swift Playgrounds for iPad app icon

Sample Project

Scroll Down

On this page

Video

On this page

What are Optionals?

Optionals are a type that represents either a wrapped value or the absence of a value.

Apple Developer Documentation

Put simply, optionals are a type that can contain a value or might contain nil, the absence of a value. Optionals are an important language feature that allows you to write safe code, properly handling missing values, and avoid dealing with unexpected errors or behaviors at run time.

Declaring Optionals

An optional type is denoted with the wrapped type's name with a trailing question mark (?).

For example, an integer type is Int while an optional integer type is Int?. This is the same with all other data types like String and String?.

In the example below, both values are optionals as they are explicitly declared as optionals.

var nonExistentNumber: Int? = nil
var aNumberThatExists: Int? = 123

Optionals also support type inference, where the compiler will automatically infer the type of your value.

In this example, Int("…") initializer may return a nil value as it attempts to convert a String into an Int type.

var number = Int("42") // This is of the type Int?
var notANumber = Int("Hello")

print(number == nil) // Prints “false”
print(notANumber == nil) // Prints “true”

Implicitly Unwrapped Optionals

Implicitly Unwrapped Optionals are declared with a trailing exclamation mark (!). While still an optional value like the ones with the trailing question mark (?), they behave differently.

var anotherNumber: Int! = 123
var anotherNotNumber: Int! = nil
var yetAnotherNotNumber:

Unlike regular optionals (like Int? and String?), which requires you to unwrap the value to access the underlying value, using implicitly unwrapped optionals (like Int! and String!) automatically unwraps itself when accessed. This means you will not need to handle optionals with the methods below every time you use value—but if value is nil when you try to use it, it will cause the application to terminate or crash.

Handling Optionals

Optional Binding

Optional binding allows you to conditionally bind the wrapped value of an Optional instance to a new variable, using if-let , guard-let, or a switch-case.

if-let

If-let allows you to set the unwrapped value to a new property and you can use the else clause to handle a case when the value is nil.

var userFavouriteNumber = 42

if let number = Int(userFavoriteNumber) {
    // number is now of type Int
    // Handle if number exists
} else {
    // Handle if number does not exist
}

This will also work within SwiftUI with conditional rendering.

if let number = Int(userFavoriteNumber) {
    Text("Your favorite number is \(number)")
} else {
    Text("That's not a number!")
}

if-let shorthand

In Swift, when using if-let to optionally bind to a property, the optional variable's name is often reused for the optionally bound property.

let name: String?

if let name = name {
    print("Hello \(name)")
} else {
    print("No name provided")
}

You can use the shorthand to avoid typing if let name = name and transform that simply into if let name. This makes it faster to write optional bindings.

let name: String?

if let name {
    print("Hello \(name)")
} else {
    print("No name provided")
}

guard-let

Guard allows you to set the unwrapped value to a new property and perform an early-exit if the wrapped value is nil.

func evaluateNumber(userFavoriteNumber: String) {
    guard let number = Int(userFavoriteNumber) else {
        // Handle if number does not exist
        return
    } 
    // number is now of type Int
    // Handle if number exists
}

The main benefit of guard-let over if-let is the ability to exit-early and avoid nesting things too deeply. Within the guard's else clause, you can write code to handle if the wrapped value does not exist, you will need to end it off with a return if within a function, or break—to end the loop or continue—to move onto the next iteration if within a loop.

While guard-let works within SwiftUI's View Builder code, it is generally better to use if-let.

guard-let shorthand

In Swift, when using guard-let to optionally bind to a property, the optional variable's name is often reused for the optionally bound property.

let name: String?

guard let name = name else {
    return
}

print("Hello \(name)")

You can use the shorthand to avoid typing guard let name = name and transform that simply into guard let name. This makes it faster to write optional bindings.

let name: String?

guard let name else {
    return
}

print("Hello \(name)")

Switch Statements

Switch Statements allows you to handle the optional value using the .some condition. You can also use it to check the wrapped value against other values.

In this example, the wrapped value, optionalNumber is checked against 42, then it is optionally bounded to the value property in the .some(let value) case. Finally, the default case handles any nil values.

let optionalNumber = Int(userFavoriteNumber)
switch optionalNumber {
case 42: 
    print("The answer to the ultimate question of life, the universe, and everything")
case .some(let value):
    print("Your favorite number is \(value)")
default:
    print("Handle if the optionalNumber is nil")
}

In the above example, the default case can also be replaced with case nil: to handle missing values.

This method, like if-let works well with SwiftUI's conditional rendering.

switch Int(userFavoriteNumber) {
case 42: 
    Text("The answer to the ultimate question of life, the universe, and everything")
case .some(let value):
    Text("Your favorite number is \(value)")
default:
    Text("You typed in an invalid number")
}

Optional Chaining

Optional chaining allows you to safely access the properties and methods of a wrapped instance, use the optional chaining operator (?).

For example, if you want to access the description property (that creates a textual description) of an optional value, you can use optional chaining to "pass along the optional value".

var userFavouriteNumber = "42"
let description = Int(userFavoriteNumber)?.description

In the above example, if Int(userFavoriteNumber) evaluates to nil, the description constant will be set to nil.

You can also use this to access functions and methods. If the value is nil, the method will not run.

myOptionalValue?.doSomething()

As the name suggests, you can chain it. When chaining, you will need to use the optional chaining operator (?) whenever you are dealing with an optional property or method that returns an optional value.

myOptionalValue?.property.doSomething()
myOptionalValue?.optionalProperty?.doSomething()

Nil-Coalescing Operator

The nil-coalescing operator (??) allows you to supply a default value in case the Optional instance is nil.

In this example, if userFavoriteNumber cannot be converted to an integer, the favoriteNumber constant will be set to 100.

var userFavoriteNumber = "42"
let favoriteNumber = Int(userFavoriteNumber) ?? 100

Unconditional Unwrapping

⚠️ Warning
Only use unconditional unwrapping when you are certain the value will return a non-nil result.

Unconditional unwrapping will terminate the application if the value is nil.

You can use the value by using the forced unwrap operator (!) to unconditionally unwrap a value.

In the example below, if myOptionalValue is nil, the application will terminate.

var myOptionalValue: Int?

var myValue = myOptionalValue

© 2024 Tinkertanker Pte Ltd / Swift Accelerator. All rights reserved.

© 2024 Tinkertanker Pte Ltd / Swift Accelerator. All rights reserved.

© 2024 Tinkertanker Pte Ltd / Swift Accelerator. All rights reserved.