Swift Optional Types-Complete Guide

Swift Optional Types-Complete Guide

Swift Optionals
This post is all about understanding the optional types in Swift. This post will tell you why we need them at first place and what we used to do in Objective C in place of Optionals. We will be using…

  • Swift Optional Types-Complete Guide

Motive

This post is all about understanding the optional types in Swift. This post will tell you why we need them in the first place and what we used to do in Objective C in place of Optionals. We will be using Swift 4.2 and playground to understand the optionals. At last, you will have a clear idea on why Optionals are valuable to programming and of-course programmers.

Optionals?

How does swift declare them?

This is the declaration of the optional type as a powerful enum

enum Optional<Wrapped> : ExpressibleByNilLiteral

An optional type is enum type which can have one of the two possible values, None and Some(T), where T is an associated value of the data type in Swift

Swift introduces Optionals type which holds a value or nothing. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”

In simple words, if you want a variable to hold some value when there is value and nothing in case of no value, then you must declare a variable optional type. In case of no value, optional types will have nil value inside it.

Why Optionals?

Let’s take an example of an objective C code

- (NSString *)computerName:(NSString *)computerId {
if ([computerId isEqualToString:@"Apple1234"]) {
return @"Apple";
} else if ([computerId isEqualToString:@"Dell1234"]) {
return @"Dell";
}
return nil;
}

You can use the computerName method to get the Computer Provider for a particular computer Id. As of now, this method returns value for the two cases and nil for others.

NSString *computerName = [self computerName:@"Lenovo1234"]; // nil is returned
NSString *preString = @"Computer Name - ";
NSString *message = [preString stringByAppendingString:computerName]; // runtime error
NSLog(@"%@", message);

This code compiles properly and but during runtime, it causes Run time exception while running the app. This is the downside of this approach. How do we solve this problem using Optionals? Let’s see

func computerName(computerId: String) -> String? {
if (computerId == "Apple1234") {
return "Apple"
} else if (computerId == "Dell1234") {
return "Dell"
}
return nil
}
var computerName:String? = computerName("Lenovo1234")
let text = "Computer Name - "
if(computerName){
let message = text + computerName
print(message)
}
Output:

As you can see, if the computerName is having a value other than nil, the message gets printed. This is the power of optionals.

How to Declare?

Swift allows two keywords to declare a type as optionals.

Using Optional Keyword

let lastName: Optional<String> = "Jain"

Using ? Symbol

Swift offers another simple and short way to declare a type as an optional type using ? symbol.

let lastName: String? = "Jain"

All types of Swift objects and primitive types can be declared as optionals.

let shortForm: Int? = Int("42")

Our Custom Like Optional Type:

Let's try to make our custom Optional Type which will work the same way as Swift Optionals. This is to understand the internal implementation of enums.

Let's name this custom optional type as CustomOptional.

enum CustomOptional<Wrapped> {
/// The absence of a value.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
}
var str: CustomOptional<String> = CustomOptional.some(“ghg”)
print(str)
str = CustomOptional.none
print(str)
Output: some(“ghg”)
Output: none

Here we can see that CustomOptional<String> is the same as Optional<String>. But swift compiler has syntactic linking of CustomOptional<String> to be declared as String? otherwise, everything is the same.

How to use Optionals?

Just like declaring, using optionals and getting value back from them is a little tricky here.

For getting the values back from optionals you have to unwrap the value. You unwrap values by using the following methods.

Unwrapping by Forced Unwrapping

To get the value back using forced unwrapping you just have to use the ! on the optional type. Example below:

First, we will try to print the value as it is.

print(lastName)
Output: Optional("Jain")

So here we get the value with the optional wrapper. You can’t directly use it in the programme. Here comes the unwrapping part

Here we are unwrapping lastName which we declared in the previous section

print(lastName!)
Output: Jain

Yes, it is that simple! :) But there is catch here, the downside of this approach is that your app will crash when you try to force unwrap an optional which is having a nil value. In simple words, unwrapping nil causes the crash. An easy and first approach would just use the if else condition for the nil check before using, same like what we have been doing in objective C.

if lastName != nil{
print(lastName!)
}
Output: Jain

Swift offers a better and a beautiful approach for safely unwrapping an optional type by Optional Binding.

Unwrapping by Optional Binding

Use optional binding to find out whether an optional type contains a value, and if so, to make that value available as a temporary constant or variable.

See the example below -

if let tempLastName = lastName{
print(tempLastName)
}
Output: Jain

Quite better, isn’t? The only downside of this approach is that this tempLastName is only accessible inside the if block, outside of this block you still don’t have a solution yet. Here come the guard statements for help. Let see how these work.

Unwrapping by Guard Statements

Using guard statements, you can unwrap an optional type for full method scope if there is a value inside the optional, if not then application returns the method.

guard if let tempLastName = lastName else {
//Do all the required work
return;
}
print(tempLastName)
Output: Jain

Here you can use tempLastName in the whole method body if there is a value inside the lastName. But if there is nil inside it, it actually breaks the function scope and app has to return that method. Before returning, you must do all the finishing work inside the else block of guard statement.

Optional Chaining

Before explaining optional chaining, we create a new class named Address with streetName, cityName, and stateName properties, and then we create another class Person which is having an address (optional) as it’s property. Now look at this example

public class Address{
var streetName: String;
var cityName: String;
var stateName: String;
init(streetName: String, cityName: String, stateName: String) {
self.streetName = streetName
self.stateName = stateName
self.cityName = cityName
}
}
class Person{
var address :Address?
}
var person = Person()
person.address = nil

As you can see, it causes run time error as you try to get the value by forced unwrapping. Let’s see how we can resolve this problem using Optional Chaining.

public class Address{
var streetName: String;
var cityName: String;
var stateName: String;
init(streetName: String, cityName: String, stateName: String) {
self.streetName = streetName
self.stateName = stateName
self.cityName = cityName
}
}
class Person{
var address :Address?
}
var person = Person()
person.address = nil
if let streetName = person.address?.streetName{
print(streetName)
}
Output:

Instead of using the streetName directly on the forced unwrapped optional we use chaining and use ? on the address and get the value with optional binding. In this case, if the address is having value, the street name will be printed on the console, otherwise, no value will be printed.

Nil coalescing

Sometimes we need a default value for nil. Suppose you have created an integer as an optional type. When the value is nil then we want 0 to be used everywhere inside the app. Let’s see how to implement it

var creditScore: Int?
creditScore = nil
var message: String = "Your Credit score is "
message = message + "\(creditScore ?? 0)"
print(message)

what does ?? do here? it actually checks if the creditScore value is nil, if so then use 0 as the value, otherwise use creditScore as the value.
Here instead of printing the credit score message as “Your Credit score is nil”, we are printing “Your Credit score is 0”. This is very handy when you are working with primitive types.

Note: Always try to avoid forced unwrapping. Either use ?? or optional binding where you are using it. This makes it safe from any unwanted crashes.

Conclusion

So here we are, we learned the optionals from declaring it to using it with optional chaining. Optional binding, Optional Chaining and nil coalescing make it more beautiful and valuable to the programming.

References and useful sources

Apple Developer Documentation: https://developer.apple.com/documentation