Skip to content

SwiftLet 04: Optionals

by: 0xLeif

Posted on:November 30, 2021 at 04:06 AM

SwiftLet #04: Optionals

What if a variable shouldn’t have a value?

Great question! Luckily Swift has what are known as Optionals. Optionals optionally have a value! Let’s say we have a variable that is the name of our favorite ice cream.

var favoriteIceCreamFlavor: String

Well let’s say we have a friend that hates ice cream, they don’t even have a least favorite flavor! You may think, wait can’t we just put nothing as the string?

favoriteIceCreamFlavor = ""

Sure! Although this could cause issues, why isn’t the favoriteIceCreamFlavor just n/a? In Swift nil is the value denoted to mean nothing or does not exist.

This is when we want to use optionals! Now we can print out the favoriteIceCreamFlavor and it will print out nil.

var favoriteIceCreamFlavor: String?

print(favoriteIceCreamFlavor) // nil

Although now, when we set the favoriteIceCreamFlavor to some flavor and print it out we get some different output than if we used just a String and not an String? (optional string).

var favoriteIceCreamFlavor: String?

favoriteIceCreamFlavor = "Coffee"

print(favoriteIceCreamFlavor) // Optional("Coffee")

For some reason we are getting our favorite ice cream flavor, but it is being wrapped with Optional. In Swift Optionals help us deal with variables that may not always have a value. If we wanted to print out favoriteIceCreamFlavor as a String and not a String?, we just need to unwrap the value! Swift has a few different ways to unwrap an Optional, the first we will discuss is the one you should almost never use!

Force Unwrap When you force unwrap an Optional in Swift it will return the unwrapped value or crash your program! Be careful!

var favoriteIceCreamFlavor: String?

favoriteIceCreamFlavor = "Coffee"

print(favoriteIceCreamFlavor!) // Coffee

If we didn’t have a favoriteIceCreamFlavor set our app would crash and give us an error.

var favoriteIceCreamFlavor: String?

print(favoriteIceCreamFlavor!)
// Fatal error: Unexpectedly found nil while unwrapping an Optional value
// Terminated due to signal: ILLEGAL INSTRUCTION (4)

Default Unwrap Instead of force unwrapping, there is always the option to provide a default value if the variable is nil!

var favoriteIceCreamFlavor: String?

favoriteIceCreamFlavor = "Coffee"

print(favoriteIceCreamFlavor ?? "N/A") // Coffee

If the variable is nil it will just default to the value we provided.

var favoriteIceCreamFlavor: String?

print(favoriteIceCreamFlavor ?? "N/A") // N/A

Conditionally Unwrap Swift also can unwrap Optionals using an if or guard statement. Simply initialize a new variable inside the conditional statement.

if let

var favoriteIceCreamFlavor: String? = Bool.random() ? "Coffee" : nil

if let unwrappedFavoriteIceCreamFlavor = favoriteIceCreamFlavor {
    print(unwrappedFavoriteIceCreamFlavor)
} else {
    print(unwrappedFavoriteIceCreamFlavor) // Error: Cannot find 'unwrappedFavoriteIceCreamFlavor' in scope
    print("None!")
}

This example will randomly set the value of favoriteIceCreamFlavor to “Coffee“ or nil. Then it will only print the ice cream flavor if it is not nil. Otherwise it will just print “None!”. Notice that unwrappedFavoriteIceCreamFlavor is a new variable and is only usage within the scope of the statement it belongs to.

var favoriteIceCreamFlavor: String? = Bool.random() ? "Coffee" : nil

if let unwrappedFavoriteIceCreamFlavor = favoriteIceCreamFlavor,
    unwrappedFavoriteIceCreamFlavor == "Coffee" {
    print(unwrappedFavoriteIceCreamFlavor)
} else if var unwrappedFavoriteIceCreamFlavor = favoriteIceCreamFlavor {
    unwrappedFavoriteIceCreamFlavor = "Coffee"
    print(unwrappedFavoriteIceCreamFlavor)
} else {
    print("None!")
}

You can even specify that the locally unwrapped variable is mutable! Which doesn’t change the original favoriteIceCreamFlavor if that variable is a Value Type. If the variable is a Reference Type, it can modify any variable that is a var and you have access to.

guard let

var favoriteIceCreamFlavor: String? = Bool.random() ? "Coffee" : nil

guard let unwrappedFavoriteIceCreamFlavor = favoriteIceCreamFlavor else {
//    print(unwrappedFavoriteIceCreamFlavor) // Error: Cannot find 'unwrappedFavoriteIceCreamFlavor' in scope
    print("None!")
    return
}

print(unwrappedFavoriteIceCreamFlavor)