jazzedge
12/1/2017 - 6:42 PM

Swift - Optionals

01. Don't Force Unwrap Optionals

Optionals are a very powerful feature of Swift. They are just types like int and String, annotated by a question mark after the type declaration. If you want to declare a variable as an optional string, you would just write:

var someVariable: String?

This tells the compiler that there either can be a value or there might be no value at all. String? and String are considered to be two different types.

Think of optionals as a gift box. As I mentioned, this gift box may or may not have a value, and if you want to find out, you must unwrap the optional first. There are many ways of doing this:

02. The Wrong Way - Forced Unwrapping

This operation (performed by using an exclamation mark) is called the Bang Operator. Don't use it! Force unwrapping your variables is never a good idea. If the value of the optional you are trying to unwrap is nil (nothing), your app will crash, and who wants that? Anyway, let's look at the following block of code:

var someVariable: String?
var somethingElse: String = "hello"
 
func setupApp() {
    self.somethingElse = self.someVariable!
}

In this example, the app would crash because we never defined a value for someVariable, and we are trying to assign it to a variable of type String. This defeats the whole purpose of optionals, which are there to help protect us from errors like this! 

Let's look at some of the correct ways of handling this same situation.

03. The Right Way- Optional Binding 

This is one of the most popular methods of dealing with optionals. In this method, you simply assign an optional value to a constant using an if statement. If the optional can be unwrapped, the compiler enters the closure, and you can use the constant that was created. Otherwise, you fall into an else statement and pretend that nothing happened. Let's look at an example of this:


var someVariable: String?
var somethingElse: String = "hello"
 
func setupApp() {
    if let theThing = someVariable {
        self.somethingElse = self.someVariable!
    } else {
        print("error")
    }
}

Using the same example as last time, but with optional binding instead, we can see that instead of crashing, the compiler enters the else statement and prints "error."

04. Optional Chaining

Another common way to safely unwrap optionals is optional chaining. This is a great way to avoid nil values cleanly, and in one line of code. When you use this method and come across a nil value, that line of code simply ceases to execute. Here's an example of this:

var someClass: SomeClass? = SomeClass()
var somethingElse: String?
 
func setupApp() {
    self.somethingElse = someClass?.createString()
}

Basically, if someClass is nil, the entire line will not execute, and the value of somethingElse will become nil. If there is a value, like the example above, it will be assigned to the variable somethingElse. In either case, the app will not crash.

05. Nil Coalescing

This method handles optionals with a single line, but unlike the method above, you need to provide a default or "else" case (in case the optional turns out to be nil). Let's look at an example:

var someVariable: String?
var somethingElse: String = "hello"
 
func setupApp() {
    self.somethingElse = someVariable ?? "error"
}

Although this may seem a little cryptic, it simply means that if the left-hand statement has a value (in other words is not nil), it will be used. If it is nil, then the default statement will be used—in this case, a hard-coded string. It is worth noting that the right-hand statement needs to be of a non-nil and non-optional type (otherwise, the purpose of this would be defeated).