Swift Optionals

Optionals are Swift's built-in way of saying a value might be missing, and the language forces you to handle that possibility before you can use it.

What Is an Optional?

In Swift, every type is non-optional by default, meaning a variable must always hold a real value of that type. An optional wraps a type to say 'this might hold a value of Int, or it might hold nothing at all.' You write an optional by appending a question mark to the type, such as Int? or String?. Under the hood, an optional is really an enum with two cases: .some(Value) or .none, but Swift gives you clean syntax so you rarely need to think about that directly.

Declaring Optional Types

Declaring and assigning optionals

var age: Int? = 25
var nickname: String? = nil

print(age)       // Optional(25)
print(nickname)  // nil

age = nil

Unwrapping with if let

Because an optional might contain nothing, Swift won't let you use its value directly without unwrapping it first. The if let syntax, called optional binding, attempts to pull the value out; if it succeeds, a new non-optional constant is created and scoped to the if block. If the optional is nil, the else branch runs instead. This is the safest and most common way to react to an optional that may or may not have a value.

Unwrapping with if let

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)

if let actualNumber = convertedNumber {
    print("'\(possibleNumber)' converted to \(actualNumber)")
} else {
    print("'\(possibleNumber)' could not be converted to an integer")
}

// Swift 5.7+ shorthand, reusing the same name:
// if let actualNumber { print(actualNumber) }

Unwrapping with guard let and Early Exit

Unwrapping with guard let

func greet(person name: String?) {
    guard let name = name else {
        print("No name provided.")
        return
    }
    // 'name' is a non-optional String from this point
    // all the way to the end of the function.
    print("Hello, \(name)!")
}

greet(person: "Ava")   // Hello, Ava!
greet(person: nil)     // No name provided.
  • Forced unwrapping (value!) — assumes a value exists and crashes at runtime if it's nil
  • Optional binding (if let, guard let) — safely extracts the value into a new constant
  • Nil-coalescing operator (??) — supplies a default value when the optional is nil
  • Optional chaining (?.) — safely calls through a chain of optionals, short-circuiting to nil
TechniqueSyntaxWhen to Use
Forced unwrapvalue!You are certain the value is not nil
if letif let x = optional { }You only need the value inside a limited scope
guard letguard let x = optional else { return }You need the value for the rest of the function
Nil-coalescingoptional ?? defaultValueYou want a fallback value instead of unwrapping
Note: Force unwrapping with ! is basically telling Swift 'trust me, it's there.' It works fine until one day it isn't there, and then your app crashes instantly. Save the exclamation mark for cases where nil truly can't happen, like an IBOutlet you just connected in Interface Builder.

Exercise: Swift Optionals

What happens if you force-unwrap (`!`) an optional that is currently `nil`?