Swift! Optionals?

If you are new to swift and to the concept of Optionals it may seems a little bit strange to have a special type for representing something or nothing, but if you get the hang of it, it will come really handy in a lot of situations.

Prerequisites

You should understand Swift Enums before continuing with this article. If you don't have any clue what an Enum is, please take the time to read through the official documentation.

Optional?

Basically, an Optional is an Enum with 2 cases and one of the cases has an associated value attached to it.

  • .Some(Wrapped)
  • .None

That's it! This is all the magic behind that mysterious thing called Optional.

An Optional is just a value wrapper. It can be empty(.None) or there is something inside of it(.Some(Wrapped)).

If you assign a value different from nil, the basic initializer gets called. It creates an Enum with the .Some state and your assigned value will be set as its associated value.

If you assign nil to an Optional swift creates a .None stated Enum for you. This is possible because the OptionalType conforms to the NilLiterableConvertible Protocol. This protocol defines that a conforming type needs an initializer that takes nil as an argument.

Inside Optionals implementation of init(nilLiteral: ()) an Optional instance with state .None will be created and assigned to itself


If you define an Optional of Type Int by appending the ? character to the Int identifier and assign a value of 10 to it

var x: Int? = 10

Swift creates an Enum of Type Optional<Int> with an associated value of 10. Its state will be .Some(10)


If you assign nil

var y: Int? = nil

You will get back an Enum of Type Optional<Int>. Its state is .None

Optionals are Enums

Because Optionals are just Enums we can also work with them like Enums.

  1. Assigning
var z: Int? = .Some(20)

2. Using switch with Optionals

let x: String? = “Hello Optional”
switch x {
  case .some(let value): print(“Value: \(value)”)
  case .none: print(“nothing stored inside the enum”)
}

3. Accessing an Optionals value using case let

if case let .Some(value) = x {
 print(value)
}

Optional Binding

Swift also provides a special syntax to access .Somes wrapped value called optional binding.

if let x = x {
  print(x)
}

You can also combine it with the guard statement to structure your functions nicely.

func foo(x: Int?) {
  guard let x = x else {
    return
  }
  // do something with x
  print(x)
}

Optional Chaining

Imagine having two Structs A & B and A having an optional stored property of Type B.

struct A {
  let b: B?
}
struct B {
  let x: Int = 100
}

Now you store an instance of A inside an Optional. How would you get the x value of B? You could accomplish your goal by nesting optional binding directives like so:

let a : A? = A(b: B())
if let a = a {
  if let b = a.b {
    print(b.x)
  }
}

This seems way to complicated, so Swift comes with an easier approach of unwrapping optionals called optional chaining.

let value = a?.b?.x

Cool, right?

Nil Coalescing Operator

The nil coalescing operator (c ?? d) unwraps an optional c if it contains a value, or returns a default value d if c is nil. The expression c is always of an optional type.

let c: Int? = 10
let d: Int = 0
let e = c ?? d

The expression d must match the type that is stored inside c. If d would be a string, it won’t compile.

let c: Int? = 10
let d: String = “Hello World”
let e = c ?? d // wont compile

Force Unwrapping

You can also get an Optionals value by placing an exclamation mark behind it. This will force unwrap your optional. That means that your program tries to get the wrapped value from .Some(wrapped) without checking if it is actually set. So if there is no value inside .Some() your app will crash.

let optional : Int? = 10
let valueOfOptional = optional!
let optionalWithNoValue : Int? = nil
let valueOfOptionalWithNoValue = optionalWithNoValue! // will crash

Implicitly Unwrapped Optionals

Sometimes you are 100% sure that your Optional contains a value. Another Scenario could be that you want that your code stops executing if an optionals value isn’t set. This is the moment where implicitly unwrapped optionals can be used. I personally don’t like to use them because they lead to unreadable code and are dangerous to use. Everything you can do with implicitly unwrapped optionals is basically possible with normal optionals too. You define an implicitly unwrapped optional by using ! instead of ?. No need to unwrap when using them.

let implicitlyOptional : Int! = 10
print(implicitlyOptional)
let anotherOne : Int! = nil
print(anotherOne) // will crash

Double-, Tripple-, Quadrupel-Optional

Optionals can also be nested into each other. Here is a little Code snippet that shows how to unwrap nested Optionals. You could also use a switch statement for that but we will stick to the native unwrapping approach with optional binding for now.

var innerOptional : Int? = 10
var outerOptional : Int?? = innerOptional
if let innerOptional = outerOptional, value = innerOptional {
print(value)
}

Map & Flatmap

The Optional-Type also provides two nice convenience functions. Map & Flatmap. Map and Flatmap unwrap the optional for you. You just need to pass a closure to them. Inside that closure, you can process the Optionals unwrapped value. The returned value will be an Optional again. The only difference between these two functions is that Map can’t handle nil as a return value.

var x : Int? = 10
let y : Int? = x.map {
  if $0 < 10 {
    return 0 // Cannot return nil
  } else { return $0 }
}
let z : Int? = x.flatMap {
  if $0 < 10 {
    return nil  
  } else { return $0 }
}

It’s a wrap

If you have managed to keep reading this article up to this point you should understand nearly each part of the Optionals official public interface.

Now have fun doing something optional ..


Feel free to add me on github, twitter, linkedin or xing if you have any questions. If you like electronic music you can also listen to my Tracks on SoundCloud ;)

Ciao!

Sebastian Boldt

Show your support

Clapping shows how much you appreciated Sebastian Boldt 👨🏻‍💻’s story.