Swift Optional Chaining

Filed Under: Swift
swift optional chaining

Swift Optional Chaining is a very useful feature. Optionals are a type in Swift that wrap primitive types and are typically used for preventing null values. For more details on Optionals refer this tutorial before proceeding ahead.

Swift Optional Chaining

Optional Chaining is the process of chaining calls on optional values such that it handles the unwrapping gracefully and concisely without giving runtime errors. As the name says, it chains multiple queries together.

But the same thing is achievable using if let,guard let and implicit unwrapping too.

What’s the need for Optional Chaining then?

Let’s look at an example in Playground first without bringing Optional Chaining.

Without Optional Chaining

Let’s assume we have the following classes:


class University {
    var city: City?
    var universityName: String = "Indian Institute of Technology"
}

class City{
    
    var cityName: String?
    var college: College?
    
}

class College{
    
    var discplines = [Discpline?]()
    var numberOfStreams : Int
    {
        return discplines.count
    }
    
}

class Discpline{
    var discplineName: String?
    var student : Student?
}

class Student{
    var name: String?
    var discpline : Discpline
    init(currentDiscpline: Discpline) {
        self.discpline = currentDiscpline
    }
    
    func printDetails() ->String  {
        return "Student Details:\n Name:\(name ?? "Na") \n Discpline: \(discpline.discplineName ?? "NA")"
    }
}

Every class contains an instance of the below class. All instances are defined as optionals.
College class holds an array of Discpline class objects.

Let’s instantiate each of these classes.


var university = University()
var myCity = City()
myCity.cityName = "Bangalore"
var myCollege = College()
var csDiscpline = Discpline()
csDiscpline.discplineName = "Computer Science"
var meDiscpline = Discpline()
meDiscpline.discplineName = "Mechanical Engineering"
myCollege.discplines = [csDiscpline,meDiscpline]

var myStudent = Student(currentDiscpline: csDiscpline)
myStudent.name = "Anupam"

Using Implicit Unwrapping
Let’s get and retrieve properties and functions from the classes using implicit unwrapping (!).


university.city = myCity
university.city!.college = myCollege
university.city!.college!.discplines = [csDiscpline,meDiscpline]
university.city!.college!.discplines[0]!.student = myStudent
var finalString = university.city!.college!.discplines[0]!.student!.printDetails()

This looks okay. But we know from the Optionals in Swift tutorial that implicit unwrapping can lead to runtime crashes since it unwraps the optional without checking if it’s nil or not.

In the above code, if we set myStudent as nil, it’ll lead to a CRASH.


university.city!.college!.discplines[0]!.student = nil
var finalString = university.city!.college!.discplines[0]!.student!.printDetails() //crash since student is nil

swift optional chaining

Let’s try using if let/if var.


if var uCity = university.city
{
    uCity = myCity
    if var uCollege = uCity.college
    {
        uCollege = myCollege
        uCollege.discplines = [csDiscpline,meDiscpline]
        if var uDiscpline = uCollege.discplines[0]
        {
            if var uStudent = uDiscpline.student
            {   uStudent = myStudent
                print(uStudent.printDetails())
            }
        }
    }
}

Too much of nesting! And that too just to set values and print the result in a very basic code with hardly a few properties in each class.

This is inefficient.

Using guard var
Let’s do the same using guard var.


func usingGuard(){
guard var uCity = university.city else{
    print("City is nil")
    return
}
uCity = myCity

guard var uCollege = uCity.college else{
    print("College is nil")
    return
}
uCollege = myCollege
uCollege.discplines = [csDiscpline,meDiscpline]

guard var uDiscpline = uCollege.discplines[0] else{
    print("Discpline is nil")
    return
}

guard var uStudent = uDiscpline.student else{
    print("Student is nil")
    return
}
uStudent = myStudent
print(uStudent.printDetails())
}

usingGuard()
//prints
//Student Details:
// Name:Anupam 
// Discpline: Computer Science

This is better than if var but still too many conditional checks. Implicit wrapping was concise and crisp but dangerous since it didn’t check the optional value before unwrapping.

This is where Optional Chaining comes to our rescue.

It’s an alternative and better form of forced unwrapping.

In optional chaining, we just need to replace !. with ?..

How does Optional Chaining work

Optional Chaining is done over optional values. It returns the desired value wrapped as an Optional. If the optional is nil, it returns an Optional(nil). Optional Chaining always gives you an optional thereby eliminating the chance of runtime crashes.

Hence two things:

  • If the type that’s been retrieved through Optional Chaining is not optional, then after the optional chaining is done, it becomes optional.
  • If the type was already optional, it’ll stay optional only. It’ll not get nested like Optional(Optional(String)).

Implementation With Optional Chaining

The below code has optional chaining implemented.


university.city = myCity
university.city?.college = myCollege
university.city?.college?.discplines = [csDiscpline,meDiscpline]
university.city?.college?.discplines[0]!.student = myStudent
var finalString = university.city?.college?.discplines[0]?.student?.printDetails()
print(finalString)

Now printDetails() was defined to return a String.

Does it?
NO.

It returns an Optional(String) since the Optional Chaining wraps the returned value with an optional.

swift optional chaining example

Accessing Subscript calls through optional chaining

Change the Discpline class to:


class College{
    
    var discplines = [Discpline?]()
    var numberOfStreams : Int
    {
        return discplines.count
    }
    subscript(i: Int) -> Discpline? {
        get {
            return discplines[i]
        }
        set {
            discplines[i] = newValue
        }
    }
    
}

Thanks to subscripts we can get rid of the discpline object invocation.


if let discpline0 = university.city?.college?[0]?.discplineName
{
    print(discpline0)
}

Note: When accessing a subscript on an optional value through optional chaining, you place the question mark before the subscript’s brackets, not after. Hence we’d done college?[0]. It gets the first discipline.

This brings an end to this tutorial. You can download the Swift Playground file from the below link.

OptionalChaining.playground.

Reference: Apple Docs

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages