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:
|
***