Optionals

How to handle optionals

How to handle optionals

As we saw in the previous chapter, Optionals are really just enum types. However, as they're deeply ingrained into the language, Swift offers a lot of additional possibilities of handling Optionals.

If Let

Certainly the most used one is the so-called if let. You're basically telling Swift "If this optional value myOptionalValue actually contains a value, please give me the contained value into the variable named myUnwrappedValue":

if let myUnwrappedValue = myOptionalValue {
  print(myUnwrappedValue)
}

If myOptionalValue is actually empty, then the print statement would never be executed. As with any typical if statement, this can also have an else expression:

if let myUnwrappedValue = myOptionalValue {
  print(myUnwrappedValue)
} else {
  print("No Value")
}

You can also combine multiple if let statements if you need to handle multiple Optional values:

if let firstValue = firstOptionalValue,
   let secondValue = secondOptionalValue,
   let thirdValue = thirdOptionalValue {
   print(firstValue, secondValue, thirdValue)
} 

Finally, you can mix and match the if let pattern with normal if expressions:

if let firstValue = firstOptionalValue,
   firstValue > 10
   let secondValue = secondOptionalValue,
   secondValue == "HTTP",
   let thirdValue = thirdOptionalValue {
   print(firstValue, secondValue, thirdValue)
} 

In this example, we only print the three values if the firstOptionalValue is not empty and has a value > 10, and if the second optional value is not empty and has the value "HTTP" and if the third optional value is not empty.

Guard

Another nice feature of Swift are the guard statements. They're basically like inverted if statements. You usually use them at the beginning of a block of code to make sure that all your requirements are held. The main difference compared to if let is that you're required to leave the current scope (i.e. return, continue, or break) if the guard does not succeed. Lets look at this nonsensical function that tries to do addition with two Optional Int values. For that to work, we need to make sure that

func addOptionals(firstNumber: Int?, secondNumber: Int?) -> Int? {
  guard let first = firstNumber, let second = secondNumber
        else { return nil }
  return first + second
}

So here, we do the guard let in order to make sure that both firstNumber and secondNumber have a value, otherwise we can't really do the addition. So if one of them (or both) don't have a value, we return early in the else { return nil} block.

Observe how with if let the code-to-be-executed is within the if braces, while with guard let it is not:

if let a = b {
  print(b)
}

guard let a = b else { return }
print(b)

This makes it easier to follow the structure of code because your main code is not nested but only at the very left side of the function.

Switch

We already mentioned this in the previous chapter, but you can also use switch to handle Optionals:

switch myOptionalValue {
case let value?: print(value)
default: ()
}

We have a whole guide on pattern matching with Swift where this is explained in much more detail.

Forced Unwrap

Sometimes, if you're absolutely sure that your Optional has a value, you can also use the forced unwrap. This tells Swift to handle this Optional value as if it was a non-optional value.

This works great, but it means that the optional has to have a value. If you try a forced unwrap on an empty optional (i.e. nil) it will cause a runtime error (meaning, crash).

let oneValue: Int? = 5
let twoValue: Int? = nil

print(oneValue!) // No Crash
print(twoValue!) // Crash

But wait, there's more. The next section in our guides discusses two additional methods of handling optionals that are also really, really useful: Optional Chaining and Map.