DEV Community

Agoi Abel Adeyemi
Agoi Abel Adeyemi

Posted on

6 1

Optionals in Swift

Absent of Data

There are situations where we wish to accept data from users and also provide an opportunity for some of the data to be optionals, meaning they are not required but should be provided if available.

func dayType(for day: String) -> String {
switch day {
case: "Saturday", "Sunday": return "Weekend"
case: "Monday", "Tuesday", "Wednessday", "Thursday", "Friday": return "Weekday"
default: return "This is not a valid date"
}
}
let result1 = dayType(for: "Sunday") //will return "Weekend"
let result2 = dayType(for: "Thursday") //will return "Weekday"
let result3 = dayType(for: "fridayys") //will return "This is not a valid date"

The constant me instance of a person provided all the data but the constant anotherPerson cannot provide all the data because he probably does not have a middlename. Hence he passed nil as the value of the middlename. Sounds cool right but the nil passed will cause an error, Why?, because we have not told swift to make the middlename optional.

What is an Optional in Swift?

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 middlename: String?
Enter fullscreen mode Exit fullscreen mode

The above means that middlename can either be a string or does not contain anything which is represented by the ?. 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. Its only an Optional value that can be set to nil, and that was the reason for the error when we passed the middlename a value of nil without specifying its a type of Optional.

var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'
Enter fullscreen mode Exit fullscreen mode

How to create an Optional?

The simplest way to create an optional in swift is to add ? in front of the type like below

var middlename: String?
Enter fullscreen mode Exit fullscreen mode

Another way is using the Optional keyword like below

var middlename: Optional<String>
Enter fullscreen mode Exit fullscreen mode

Using (unwraping) an optional

The simplest way to unwrap an optional is to add a !after the optional name.

enum Day {
case Sunday
case Monday
case Tuesday
case Wednessday
case Thursday
case Friday
case Saturday
}
/** Rewriting the date type function */
func dayType(for day: Day) {
switch day {
case Day.Saturday, Day.Sunday:
return "Weekend"
case Day.Monday, Day.Tuesday, Day.Wednessday, Day.Thursday, Day.Friday
return "Weekday"
}
}
let result1 = dayType(for: Day.Sunday) //will return "Weekend"

Notice the \(middlename!), the ! there is use to unwrap the middlename so we can get the value “abel”. The problem is that when we passed a nil value to the middlename, we will get a runtime crash which says nil is Unexpected.

/** Rewriting the date type function */
func dayType(for day: Day) {
switch day {
case .Saturday, .Sunday:
return "Weekend"
case .Monday, .Tuesday, .Wednessday, .Thursday, .Friday
return "Weekday"
}
}

Before unwrapping, we need to be sure that there’s a value. So therefore we are going to continue the rest of the article with how to check before using (unwrapping) optionals.

Use If to Check for nil before force unwrapping:

Since it was nil that was passed to the variable when we initialized the Person struct, we can use an if statement to check for nil before unwrapping the Person struct like below

// You can also map to strings
enum Week: String {
case Sunday = "Weekday"
case Monday = "Weekday"
case Tuesday = "Weekday"
case Wednessday = "Weekday"
case Thursday = "Weekday"
case Friday = "Weekend"
case Saturday = "Weekend"
}
// You can also map to Int
enum Movement: Int {
case Left = 0
case Right = 1
case Top = 2
case Bottom = 3
}
// Or to floating point
enum Constants: Double {
case π = 3.14159
case e = 2.71828
case φ = 1.61803398874
case λ = 1.30357
}

Whenever we use the ! symbol, it is denoted as force unwrapping the optional value, but it a common practice to avoid force unwrapping it, because we can write our code in such a way that swift will automatically unwrap it for us

Using Optional binding:

With optional binding, though we are still using if, swift provide a way for us to use the if let statement then automatically unwrap it for us like below

/** associate without labels */
enum Trade {
case Buy(String, amount)
case Sell(String, Int)
}
Trade.Buy("Firstbank PLC", 300)
Trade.Sell("Firstbank PLC", 700)
/** associate with labels */
enum Trade {
case Buy(stock: String, amount: Int)
case Sell(stock: String, amount: Int)
}
Trade.Buy(stock: "Firstbank PLC", amount: 300)
Trade.Sell(stock: "Firstbank PLC", amount: 700)

Using Guard for early exit:

Guard provide a way to quickly exit when checking for the optional string and make our code much more cleaner hence there wont be need for if else statement.

enum AppleDevice {
case iPad
case iPhone
case AppleTv
case AppleWatch
func description() -> String {
return "This is an apple device"
}
}
AppleDevice.iPad.description() //will return "This is an apple device"
AppleDevice.iPhone.description() //will return "This is an apple device"

We have covered how to use optionals in swift, let us look at some cool secondary use cases of optionals which include using multiply optionals, method chaining and Nil Coalescing.

enum AppleDevice {
case iPad, iPhone, AppleTv, AppleWatch
func description() -> String {
switch self {
case .iPad: return "\(self) was introduced 2006"
case .iPhone: return "\(self) was introduced 2007"
case .AppleTv: return "\(self) was introduced 2010"
case .AppleWatch: return "\(self) was introduced 2014"
}
}
}
AppleDevice.iPad.description() //will return "iPad was introduced 2006"
AppleDevice.iPhone.description() //will return "iPhone was introduced 2007"

The streetName in the Street class is an optional string, the House class has a street variable which is also a Optional Street. The Person class too has a variable house which is an Optional house. When we have to access the person street. To access the person street (myStreet), we ain’t sure if the person gave us the house information (myHouse). That was the reason why we use the if let myHouse = Person.house. If the Person.houseis empty, the if statement will fail to execute, else the variable will be assigned to the myHouse property. Next, we have to access the myHouse.street and if its available, the variable will be assigned to the myStreet.

if let myHouse = Person.house, let myStreet = myHouse.street {
print(myStreet) //this will access the street
}

The pattern used to access the myStreet can be improved with the use of optional chaining like below:

//if the Person.house fails, it wil not get to the street
//which can either return a null or the street
let myStreet = Person.house?.street
//to make sure we get a value, we can include the if let like below
if let myStreet = Person.house?.street {
print(myStreet)
}

I am happy to share this article with you. If you’ve enjoyed this article, do show support by loving it . Thanks for your time and make sure to follow me or drop your comment below 👇

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (1)

Collapse
 
rinzler profile image
Rinzler

Hello there. Thanks for the very enlightening text, but the code snippets seems to be mistankenly placed, as seen in the screen shot below:

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay