Saturday, March 31, 2018

Swift 4 Introduction Series 1.6 - Swift Data Type Optionals

Optionals



Optionals is a postfix operator that can be attached to any data type. Optionals is represented by a question mark (?). We use optionals to indicate that the data type which the variable are assigned to could contain no value. We use the keyword (nil) to assign an optional with no value. Only variables that are declared as optionals can be assigned with nil value.


We declared optional variable in some situation where we would not know that if an input source contains data. Optionals make the program safer to code.


For example, a variable that is declared as (Int?); tell the system that the variable may not have any value. We can test if the variable has value and if it has value, we can unwrap the value from the variable.


Declaring Optionals

The syntax for indicating or declaring an optional are as follows:


<data_type>?


For example, to declare an optional variable we do the following:


var someOptional1: Int?
var someOptional2:String?
var someOptional3:Double?
var someOptional4:Bool?

someOptional1
someOptional2
someOptional3
someOptional4




Please note that when declaring optionals we do not need to initialize the variables because optionals data type variables are automatically initialized as no value or nil. However auto initialization only applies to variable and NOT constant.


We can set the optionals with value and reset them to nil if the program requires a nil settings.


Example:


// Continuation from previous code
someOptional1 = 766
someOptional3 = 7123.98
someOptional4 = false

someOptional1 = nil
someOptional4 = nil

someOptional1
someOptional2
someOptional3
someOptional4




Please note that optionals is not found in Objective C. Although we can set an object to nil in Objective-C, nil in Objective-C refers to a null pointer whereas in Swift, we can set any data type to optionals.


We can also declared and assigned optionals at the same time. Please note that data inference does not worked here since optionals are consider different data type from String, Int, Bool or Double. Example below:


var someOptional5:Int? = 823
let someOptional6:Bool? = false
var someOptional7:Double?
let someOptional8:String? = "Fixed Words"

someOptional5
someOptional6
someOptional7
someOptional8




As we can see from the example above, if we failed to assigned data, the variable will be set to nil by default.


Please note that when we declare constant optional, the system would not initialized into default as mentioned above. Declaring optional without data will keep the constant in possible error state. See example below:


let someOptional9:Bool? = nil
let someOptional10:Int?
let someOptional11:Double?
let someOptional12:String? = "This is text"

someOptional9
//someOptional10
// Attempt to access data from someOptional10 will generate error

// We must assigned declared variable first
someOptional10 = 1242
someOptional11 = nil

//accessing data
someOptional9
someOptional10
someOptional11
someOptional12




When we convert a number from string to integer, it is automatically returned as optional. When we convert from string to integer, the integer being assigned to is automatically declared as optionals since the value from the string may not contain a valid number. The system automatically assigned converted variable as optionals




In the following example, the conversion from text to integer failed because 102 is written as 1o2. Optional integer gracefully set the constant as nil since conversion failed.




Example:


let someText2 = "214585"
let someNumber2 = Int(someText2)

let someText3 = "214565s785"
let someNumber3 = Int(someText3)




Examine Optionals

We can use if statement and comparison operation to examine optionals to see if it is nil.


Example:


let someText4 = "214585"
let someNumber4 = Int(someText4)

if someNumber4 != nil {
   print("Conversion for someText4 is successful.")
} else {
   print("Conversion someText4 failed")
}

let someText5 = "214565s785"
let someNumber5 = Int(someText5)

if someNumber5 != nil {
   print("Conversion for someText5 is successful.")
} else {
   print("Conversion someText5 failed")
}




Forced Unwrapping Optionals

The term forced unwrapping optionals is used to extracting data from optionals. When we use force unwrapping we are telling the system that we are sure that the optionals contains data and we want to extract that data. Therefore forced unwrapping should not be used without checking for nil value.


Forced unwrapping optionals works by adding the unwrapping indicator (!) behind the variable. Using the indicator, we tell the system that we know that there is value in the optional and therefore we would like to extract its data.


We should use forced unwrapping together with if statement to check if the optional has value. When we use string interpolation with optionals we need to use forced unwrapping to extract the data.
Using the previous example, we will force unwrapped the optionals:


let someText6 = "214585"
let someNumber6 = Int(someText6)

if someNumber6 != nil {
   print("Converted someText6 is \(someNumber6!).")
} else {
   print("Conversion to someText6 failed")
}

let someText7 = "214565s785"
let someNumber7 = Int(someText7)

if someNumber7 != nil {
   print("Converted someText7 is \(someNumber7!).")
} else {
   print("Conversion for someText7 failed")
}




The following example will demonstrate what happen we use transfer the data from optionals. When we assigned optionals to another variable or constant, it will become optionals


let someOptionals13:Int? = 104

let someOutput1 = someOptionals13


let someOptionals14:String? = nil

let someOutput2 = someOptionals14




However, if we use forced unwrapping. The assigned constant or variable will be interpreted as non-optional since we forced unwrapped the optionals. Therefore, using forced unwrapping is similar to the words "We know that there is data in the optionals, please treat the optionals as non-optionals".


let someOptionals15:Int? = 104

let someOutput3 = someOptionals15!




The above example is just for illustration purpose. It is not recommended to use forced unwrapping without checking for nil. After all, the purpose for using optionals is because there is a possibility of no value.


The example belows shows what happen when we forced unwrap an optional when it contain nil value.




The following shows when we use forced unwrapping in string interpolation without checking for nil.




The conclusion is that we should not use forced unwrapping without check for nil. There are only very few situation that forced unwrapping is warranted.

Optional Bindings



By combining optionals, let keyword and if statement, we can perform checks and execute instructions only when there is value in the optionals. Optionals bindings is safer to use and we do not have to perform force unwrapping.


The syntax is as follows:


if let <any_constant_name> = <optionals> {
<statement to execute>
}


Example:
In this program, we can check if the conversion is successful as follows:


let someInput1 = "214585"

if let inputValue1 = Int(someInput1) {
   print("Conversion successful! The converted number is \(inputValue1)")
   // continue other execution
} else {
   print("Conversion failed")
}




Please note that the statement let inputValue1 = Int(someInput1) without if in front will assign inputValue1 as optionals. However, if we use optional binding by adding an if statement in front of the let statement, the system will assign inputValue1 as integer. Even if conversion failed, it would not generate error because the if statement is used as a guard or checking mechanism. The system will not create the constant inputValue1.  Please also note that force unwrapping is not necessary.


If conversion failed, we can jump into remediation instruction to exit program gracefully. Using the same example, we create a type as shown below:


let someInput1 = "214S85"

if let inputValue1 = Int(someInput1) {
   print("Conversion successful! The converted number is \(inputValue1)")
   // continue other execution
} else {
   print("Conversion failed")
}




Please note that inputValue1 is still integer. When the conversion failed, the if statement will gracefully ignore the conversion and jump to else statement.


Optional bindings tell the system that if the Int conversion is successful, pass the converted number to the constant and execute the statement contain within the if braces. However, if the conversion fails execute the else statement contain within the if braces.

Please also note that we can also use variable instead of constant in optional binding. To use variable in optional binding, use (if var) instead of (if let).  


We can also include a more complex conditional evaluation statement using optional binding.


let numberOne = "8872"
let numberTwo = "144"

if let firstNumber = Int(numberOne), let secondNumber = Int(numberTwo), firstNumber > secondNumber {
   print("\(firstNumber) > \(secondNumber). Thats all.")
} else {
  print("Either numberOne or numberTwo conversion failed or NumberTwo is bigger than NumberOne.")
}




If one of the number conversion failed or in the second number is larger than the first, it will print the else message.






Please note that constant or variable created using optional binding are only available with the body of if statement. In the previous example, we cannot use the constant within the else statement. We can only use the constant within the if statement.


Implicitly Unwrapped Optional

We define optional because there is a possibility that there is no value in the optionals. We use if statement or optional binding to check and confirm if there is value in the optionals. However, in some situation, we know that as soon as the optionals are set, there must a value. In such cases, we can define implicitly unwrapped optional. We declared implicitly unwrapped optionals using syntax as follows:


let/var <optionals_name>:<data_type>!


Example:


//: Playground - noun: a place where people can play
import UIKit

var someImplicitOptionals:Int!
func initialization () {
   someImplicitOptionals = 10
}

initialization()
print(someImplicitOptionals)




In the example above, we create an optional with implicit unwrapping because we know that after the initialization function is executed, there must be a value in the optonal. Notice that we do not need to use force unwrapping when printing the variable.


What happens if the program failed to run initialization? The variable will be default to optional.


In this way, we can use the optional that are implicitly unwrapped without using any force unwrapping. In the event that initialization fails, the variable will fall back as optional. No error will generate.


The following example will demonstrate further the difference between optionals and implicit wrapped optionals.


let someOptionals100:Int? = 10928
print(someOptionals100!)

let someImplicitOptional100:Int! = someOptionals100
print(someImplicitOptional100)




As shown above, we may need to use force unwrapping when dealing with optionals, whereas we can use implicitly unwrapped optional like a normal variable.


Please note that when we use implicitly unwrapped optional in situation that could not accept nil, it will generate runtime error when there is no value. Therefore, it is a good practice to use optional binding or check with if statement to rule out nil.


Example:
Continue from previous example


// Continue with previous example
if let checkImplicitOptional = someImplicitOptional100 {
   print("Everything is ok for this optional number \(checkImplicitOptional)")
}

let someWrongImplicitOptional:Int! = nil
if let checkImplicitOptional = someWrongImplicitOptional {
   print("Everything is ok for this second optional number \(checkImplicitOptional)")
} else {
   print("Something is wrong. This number appears to be nil.")
}




In the example above, optional binding was used to check if the implicitly unwrapped optional is nil.


The primary application of implicitly unwrapped optional in dealing with class is initialization and working with class objects. We will discuss further when we cover class and objects.



Summary

In summary, please follow the following points when dealing with optionals:


  • Please use optional when we know that there is a possibility of no value (nil) in your variable or constant. Appending the data type with ? for optionals.
  • Please use implicitly unwrapped optionals when we know that when program is loaded, the variable will contain data.
  • Please use optional binding or simple if statement to check for nil when working with statement that must require some value in order to avoid runtime error.
  • Please use optional binding or simple if statement for optionals and implicitly unwrapped optionals.


***