Optionals Chainings by Example - Swift Programming Language

1. Introduction

An optional in Swift is a type that can hold either a value or no value. Optionals are written by appending a ? to any type:

var optionalName: String? = "Developer Insider"
print(optionalName)

//prints "Optional("Developer Insider")"

Optionals are one of the most difficult Swift concepts to understand. Because of how they are written and used, it's easy to get a wrong idea of what they are. Compare the optional above to creating a normal String:

var normalName: String = "Developer Insider" // No "?" after String
print(normalName)

//prints "Developer Insider"

From the syntax it looks like an optional String is very similar to an ordinary String. It's not. An optional String is not a String with some "optional" setting turned on.

Here's the most important thing to know: An optional is a kind of container. An optional String is a container which might contain a String. An optional Int is a container which might contain an Int. Think of an optional as a kind of parcel. Before you open it (or "unwrap" in the language of optionals) you won't know if it contains something or nothing.

You can see how optionals are implemented in the Swift Standard Library by typing "Optional" into any Swift file and ⌘-clicking on it. Here's the important part of the definition:

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

Optional is just an enum which can be one of two cases: .none or .some. If it's .some, there's an associated value which, in the example above, would be the String "Hello". An optional uses Generics to give a type to the associated value. The type of an optional String isn't String, it's Optional, or more precisely Optional<String>.

2. How to create optionals

To create an optional, append a ? after the type you wish to wrap. Any type can be optional, even your own custom types. You can't have a space between the type and the ?.

var name: String? = "Developer Insider" // Create an optional String that contains "Developer Insider"

// A class with a String and an optional String property
class Car {
    var modelName: String = "" // must exist
    var internalName: String? // may or may not exist
}

var myCar: Car? = Car() // An optional "Car" (custom type)

3. Only optionals can be nil

You can only set a optional variable to nil

var optionalName: String? = "Developer Insider"
name = nil // Set name to nil, the absence of a value

If you try to set a non-optional variable to nil, you'll get an error.

var normalName: String = "Developer Insider"
normalName = nil // error: nil cannot be assigned to type 'String'

4. Forced Unwrapping

An optional String cannot be used in place of an actual String. To use the wrapped value inside an optional, you have to unwrap it. The simplest way to unwrap an optional is to add a ! after the optional name. This is called "force unwrapping". It returns the value inside the optional (as the original type) but if the optional is nil, it causes a runtime crash. Before unwrapping you should be sure there's a value.

var optionalName: String? = "Developer Insider"
let unwrappedName = optionalName!
print("Unwrapped name: \(unwrappedName)")

//prints: Unwrapped name: Developer Insider

optionalName = nil
let nilName = optionalName! // Runtime crash. Unexpected nil.

5. Optional Chaining

Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.

You specify optional chaining by placing a question mark (?) after the optional value on which you wish to call a property, method or subscript if the optional is non-nil. This is very similar to placing an exclamation mark (!) after an optional value to force the unwrapping of its value. The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.

Let's create two class, Human and Apartment. Where Human class contains a String property, name and a method, sayHello() and Apartment class contains a property whose type is Human?

class Human {
    var name: String
    init(name: String) {
        self.name = name
    }

    func sayHello() {
      print("Hello, I'm \(name)")
    }
}

class Apartment {
  var human: Human?
}

Now, let's create an instance of Apartment and assign its human property.

var seoulApartment = Apartment()
seoulApartment.human = Human(name: "Vineet")

Now, try to grab the human property of seoulApartment. Since the type of human is optional, ? gets added automatically. When you access a property whose type is optional, Swift will add ?. Anything that comes after the ? will be optional.

var myName = seoulApartment.human?.name // Always return an `optional` type since human is `optional`.
print(myName)

//prints "Optional("Vineet")"

myName is an optional type. Therefore, unwrapping is needed. Swift offers a shortcut using if let. This is called "optional binding".

if let residentName = seoulApartment.human?.name {
    print(residentName) // non-optional
} else {
    print("No name available")
}

//prints "Vineet"

You can download the swift playground of all above examples from Here




Related Article