Return to site

Best practices for unwrapping objects in swift iOS

· iOS App Development

Intro

Unwrapping an optional is a common process in App development for the Apple ecosystem. Multiple ways of unwrapping are possible, but picking the right one is sometimes challenging.

Problem statement

Before begin, let’s discuss, what is Optional in Swift?

In Swift, an optional can contain either a real value or nil (null for other languages), which indicates no value. The optional object can be denoted with a question mark (?). Following example will give you the differences between the normal variable and operational variable declaration.

1 var fname: String

2 var lname: String?

1st statement is to declare a variable “frame”, typed String. Now it is mandatory to assign a String typed value into this variable, before move further. Otherwise, it will lead you to a compiler error.

The 2nd statement allows to declare a variable “lname”, optional typed String (with? mark). So here it is not mandatory to assign any real value into it, as it can work with no value (nil). We need to have optional variables in many cases, where you are not sure about the values for these variables. For example, the user should enter “First Name” so “fname” is mandatory to have value. But “Last Name” the user may enter or may skip, so “lname” is optional here, i.e can accept value as well nil. Same way, if there is a TextField and user needs to enter the inputs value, then make sure to use optional for that TextField, so that, if TextField value is empty, i.e. nil, still the App should run, without a crash.

But when a nullable object’s value needs to get access further in code body, make sure that the object should have a real value assigned to it. Otherwise, a runtime error will generate, wherever the compiler found nil while unwrapping.

To avoid that we applied forcefully unwrapping using “force unwrapped” symbol with that object, i.e exclamation mark (!). This said to the compiler that, the optional object has value in it.

For example,

1 var num: Int?

Here, variable “num” can accept optional Int value, that means, “num” can be nil too. So to access this “num” value, don’t forget to add real value, here Int type, into it and then unwrapped it while utilizing.

2 num = 12

3 print(“Num is: \(num!)”)

Here, in 2nd statement, we assigned Int 12 into “num”. And in 3rd statement, we are trying to print the value of “num”. Notice the exclamation mark (!), which is telling the compiler that, the “num" is not nil and it has a valid value in it. Without any error, these three lines will work, and as output, we can get,

Num is: 12

It is the most common way to do unwrapping of an object in Swift. This exclamation (!) will apply to any variables and outlets.

The major issue with force unwrapping is if the value is nil for that object. For example, here if the 2nd statement is not present, then be ready to get runtime error for 3rd statement.

1 var num: Int?

2 //num = 12

3 print(“Num is: \(num!)”)

fatal error: unexpectedly found nil while unwrapping an Optional value

Here, the compiler knows that “num” has some real value and desperately is trying to get access that value, because the “num” has “!” symbol with it. But in reality “num” doesn’t have, any value (nil by default). So the fatal error occurred.

Solutions

The above problem is common with Swift iOS app development. There are two different ways to safely unwrapped an optional value, rather forcefully.

SOLUTION 1: IF-LET-ELSE

If we re-write the code as follows,

1 var num: Int?

2 num = 12

3 if let temp = num{

4 print("Num is: \(temp)")

5 }else{

6 print("Num is nil”)

7 }

Without any issue, the output would be,

Num is: 12

Now if we comment the 2nd statement then same code may looks like,

1 var num: Int?

2 //num = 12

3 if let temp = num{

4 print("Num is: \(temp)")

5 }else{

6 print("Num is nil")

7 }

Then the result would be,

Num is nil

Here, using IF-LET, we copy the stored value of “num” variable into another, say “temp”. If “num” has value, it will be, displayed else the ELSE block will execute. So, our code won’t crash in any situation, doesn’t matter whether the “num” has real value in it or not.

SOLUTION 2: GUARD

Guard statement works almost like IF-LET-ELSE with little difference. Mostly we use a guard when we need to exist from a function abnormally if an object found nil. For example,

1 func check(num: Int?){

2 guard let temp = num else{

3 print("Num is nil")

4 return

5 }

6 print("Num is: \(num!)”)

7 }

We have created a check function, where “num” is again an optional Int type, used here as function’s argument. Then we guard the value assigning statement such way if “num” is nil then program control should exit from the function without moving further into that function else program control continues with the other statements of that function. Now if we try to call the function with and without “num” value, it will execute with no issues.

8 check(num: nil)

The output would be,

Num is nil

8 check(number: 12)

Now the output would be,

Num is: 12

Note: Notice here, in 7th statement, with “num” variable, we have used force unwrapped symbol (!). Without that, the code will execute, but the output would look like,

Num is: Optional(12)

This extra string “Optional” says “num” is an optional variable. As we used the guard statement, without any harm we can easily use “!” symbol with “num” for a clean output.

Extra: We can use Ternary Condition (? :) for this purpose. For example,

1 var num: Int?

2 num = 12

3 num != nil ? print("Num is: \(num!)") : print("Num is nil”)

Check out the 3rd statement of above code. By this time, you can guess the outputs of same.

Conclusion

It is the developer’s responsibility to unwrap the optional variable, securely. Depending on the situation, one can choose any of the safe ways of unwrapping from IF-LET-ELSE and GUARD. Try to avoid force unwrapping, until you implemented, a guard statement for an optional object.