Unwrapping an optional

There are multiple ways to unwrap an optional. All of them essentially assert that there is truly a value within the optional. This is a wonderful safety feature of Swift. The compiler forces you to consider the possibility that an optional lacks any value at all. In other languages, this is a very commonly overlooked scenario that can cause obscure bugs.

Optional binding

The safest way to unwrap an optional is to use something called optional binding. With this technique, you can assign a temporary constant or variable to the value contained within the optional. This process is contained within an if statement, so that you can use an else statement when there is no value. Optional binding looks similar to the following code:

if let string = possibleString {
    print("possibleString has a value: (string)")
}
else {
    print("possibleString has no value")
}

An optional binding is distinguished from an if statement primarily by the if let syntax. Semantically, this code is saying, "if you can let the constant string be equal to the value within possibleString, print out its value; otherwise, print that it has no value." The primary purpose of an optional binding is to create a temporary constant that is the normal (non-optional) version of the optional.

We can also use a temporary variable in an optional binding:

possibleInt = 10
if var actualInt = possibleInt {
    actualInt *= 2
    print(actualInt) // 20
}
print(possibleInt) // Optional(10)

Note that an asterisk (*) is used for multiplication in Swift. You should also notice something important about this code. If you put it into a playground, even though we multiplied the actualInt by 2, the value within the optional does not change. When we print out possibleInt later, the value is still Optional(10). This is because even though we made actualInt a variable (otherwise known as mutable), it is simply a temporary copy of the value within possibleInt. No matter what we do with actualInt, nothing will get changed about the value within possibleInt. If we have to update the actual value stored within possibleInt, we simply assign possibleInt to actualInt after we are done modifying it:

possibleInt = 10
if var actualInt = possibleInt {
   actualInt *= 2
   possibleInt = actualInt
}
print(possibleInt) // Optional(20)

Now, the value wrapped inside possibleInt has actually been updated.

A common scenario that you will probably come across is the need to unwrap multiple optional values. One option is to simply nest the optional bindings:

if let actualString = possibleString {
    if let actualArray = possibleArray {
        if let actualInt = possibleInt {
            print(actualString)
            print(actualArray)
            print(actualInt)
        }
    }
}

However, this can be a pain, as it increases the indentation level each time to keep the code organized. Instead, you can actually list multiple optional bindings into a single statement separated by commas:

if let actualString = possibleString,
    let actualArray = possibleArray,
    let actualInt = possibleInt
{
    print(actualString)
    print(actualArray)
    print(actualInt)
}

This generally produces more readable code.

Another great way to do a concise optional binding within functions is to use the guard statement. This way, you can do a series of unwrapping without increasing the indent level of the code at all:

func someFunc2() {
    guard let actualString = possibleString,
        let actualArray = possibleArray,
        let actualInt = possibleInt
    else {
        return
    }

    print(actualString)
    print(actualArray)
    print(actualInt)
}

This construct allows us to access the unwrapped values after the guard statement, because the guard statement guarantees that we would have exited the function before reaching that code, if the optional value was nil.

This way of unwrapping is great, but saying that optional binding is the safest way to access the value within an optional, implies that there is an unsafe way to unwrap an optional. This way is called forced unwrapping.

Forced unwrapping

The shortest way to unwrap an optional is to use forced unwrapping. It is done using an exclamation mark (!) after the variable name when being used:

possibleInt = 10
possibleInt! *= 2
print(possibleInt) // "Optional(20)"

However, the reason it is considered unsafe is that your entire program will crash if you try to unwrap an optional that is currently nil:

nilInt! *= 2 // fatal error

The complete error you get is unexpectedly found nil while unwrapping an optional value. This is because the forced unwrapping is essentially your personal guarantee that the optional truly does hold a value. That is why it is called "forced".

Therefore, forced unwrapping should be used in limited circumstances. It should never be used just to shorten up the code. Instead, it should only be used when you can guarantee from the structure of the code that it cannot be nil, even though it is defined as an optional. Even in that case, you should see if it is possible to use a non-optional variable instead. The only other place you may use it is if your program truly could not recover from an optional being nil. In those circumstances, you should at least consider presenting an error to the user, which is always better than simply having your program crash.

An example of a scenario where it may be used effectively is with lazily calculated values. A lazily calculated value is the one that is not created until the first time it is accessed. To illustrate this, let's consider a hypothetical class that represents a file system directory. It will have a property listing its contents that is lazily calculated. The code will look similar to the following code:

class FileSystemItem {}
class File: FileSystemItem {}
class Directory: FileSystemItem {
    private var realContents: [FileSystemItem]?
    var contents: [FileSystemItem] {
        if self.realContents == nil {
            self.realContents = self.loadContents()
        }
        return self.realContents!
    }

    private func loadContents() -> [FileSystemItem] {
        // Do some loading
        return []
    }
}

Here, we have defined a superclass called FileSystemItem that both File and Directory inherit from. The content of a directory is a list of FileSystemItem. We define contents as a calculated variable and store the real value within the realContents property. The calculated property checks if there is a value loaded for realContents; if there isn't, it loads the contents and puts them into the realContents property. Based on this logic, we know for 100% certainty that there will be a value within realContents by the time we get to the return statement, so it is perfectly safe to use forced unwrapping.

Nil coalescing

In addition to optional binding and forced unwrapping, Swift also provides an operator called the nil coalescing operator to unwrap an optional. This is represented by a double question mark (??). Basically, this operator lets us provide a default value for a variable or operation result, in case it is nil. This is a safe way to turn an optional value into a non-optional value and it would look similar to the following code:

var possibleString: String? = "An actual string"
print(possibleString ?? "Default String") // "An Actual String"

Here, we are asking the program to print out possibleString unless it is nil; in which case, it will just print "Default String". Since we did give it a value, it printed out that value and it is important to note that it printed out as a regular variable, not an optional. This is because one way or another, an actual value was going to be printed.

This is a great tool for concisely and safely unwrapping an optional when a default value makes sense.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset