Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Swift 4 Programming Cookbook

You're reading from   Swift 4 Programming Cookbook 50 task-oriented recipes to maximise Swift 4 productivity

Arrow left icon
Product type Paperback
Published in Sep 2017
Publisher Packt
ISBN-13 9781786460899
Length 384 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Keith Moon Keith Moon
Author Profile Icon Keith Moon
Keith Moon
Arrow right icon
View More author details
Toc

Table of Contents (9) Chapters Close

Preface 1. Swift Building Blocks FREE CHAPTER 2. Building on the Building Blocks 3. Data Wrangling with Swift Control Flow 4. Generics, Operators, and Nested Types 5. Beyond the Standard Library 6. Swift Playgrounds 7. Server-Side Swift 8. Performance and Responsiveness in Swift

Optionals, unwrap, and force unwrap

In the real world, we don't always know the answer to a problem, and problems can occur if we blindly assume that someone does. The same is true in programming languages, especially when dealing with external systems that we may not control. In many languages, including Objective-C (until recently), there was no way to indicate that something being declared may not exist at the time you attempt to access it. This would lead to either fragile code that could have broken if a nil unexpectedly found its way in or tests being run all over the code to ensure that a value did exist where it was needed, which added complexity and increased the boilerplate code that had to be written.

The nil or null term is used in programming languages to denote the absence of a value, not to be confused with the number 0 as the value or the empty (zero length) string "", they would be something, this... is nothing. Swift uses nil, and this can be assigned to a variable to remove any value currently assigned, replacing it with nil or nothing.

With a focus on Swift being type-safe and making it easier to write safe code, this ambiguity had to be addressed, and the Swift language does this with the use of optionals.

Getting started

Enter the following into the playground:

var dayOfTheWeek: String = "Monday" 
dayOfTheWeek = "Tuesday"
dayOfTheWeek = "Wednesday"
dayOfTheWeek = nil

When you try to run the code, you'll see that the compiler has raised an error and will not let you assign nil to the dayOfTheWeek variable. Quite right too--the day of the week might change, but there will never not be a current day of the week.

As we declared the type to be String, that is what the compiler expects, and nil is not a String, so it can't be assigned to this variable.

The same is true even if you remove the type declaration and have the compiler infer it, as we did in the preceding recipe. This is the type inferred at the point the variable is declared, and since it is being assigned a string value, the type of String is inferred. All other uses of this variable are checked against this inferred type of String.

Delete the last line, as the compiler issue will prevent us from running further code in the playground.

How to do it...

We will look at a different scenario where it is appropriate to have an optional variable. Melody and Finn are playing a game. In each round, Finn will hold his hand behind his back and choose a number of fingers to hold up, Melody will guess how many, and Finn will show her how many fingers he had chosen to hold up.

To help keep track of the game, Melody stores how many fingers Finn has held up in a variable. When Finn shows his hand, Melody can enter a value for the number of fingers, but when Finn's hands are behind his back, Melody doesn't know how many fingers Finn is holding up, and so can't store a value for how many fingers are being held up.

Let's enter the following code:

// Start of the game
var numberOfFingersHeldUpByFinn: Int?
// Finn's hand behind his back
numberOfFingersHeldUpByFinn = nil
// Finn shows his hand
numberOfFingersHeldUpByFinn = 3
// Finn puts hand back behind his back
numberOfFingersHeldUpByFinn = nil
// Finn shows his hand
numberOfFingersHeldUpByFinn = 1
print(numberOfFingersHeldUpByFinn)
// End of the game
let lastNumberOfFingersHeldUpByFinn: Int = numberOfFingersHeldUpByFinn!

Unlike the day of the week example, this code compiles without issues, despite the fact that we assign nil to the variable.

How it works...

We know that there will be time during the game when we don't know how many fingers are being held up, so the variable is optional--it may be an Int or it maybe nil. You will remember from earlier that nil does not mean 0. It is entirely possible that the other player may be holding up zero fingers (that is, a clenched fist) as this is a valid answer. In this scenario, nil represents a lack of knowledge about the number of fingers. To declare this variable as optional, we define the expected type, but with an additional ?:

var numberOfFingersHeldUpByFinn: Int? 

In Swift, this is referred to as an optionally wrapped Int. We have wrapped the Int type in the concept of being optional. I am emphasizing this term wrapping because we will need to unwrap this optional type later on. At the start of the game, we don't know how many fingers are being held up, so we assign nil to this variable, which is allowable for optional variables:

numberOfFingersHeldUpByFinn = nil 

Once Finn's hand is shown and we know how many fingers he has held up, we can assign that Int value to the variable:

numberOfFingersHeldUpByFinn = 3 

Since the variable type is an optional Int, the valid values are either an Int or nil; if we try something of another type, we will get a compiler error:

numberOfFingersHeldUpByFinn = "three" // Doesn't compile because "three" isn't an Int or nil

As we discussed earlier, Swift has a static type system, so the type of a variable can't be changed after it is declared. Therefore, although we have assigned a value of the Int type to the variable, this hasn't changed the variable type to the non-optional Int; its type remains Int?, an optional Int. Since the type is still optional, we can assign it a nil value when Finn puts his hands behind his back again:

numberOfFingersHeldUpByFinn = nil  

When we print an optional variable, the output tells us that it is optional, for example, Optional(1):

numberOfFingersHeldUpByFinn = 1 
print(numberOfFingersHeldUpByFinn)

You will notice that the compiler highlights an issue that says Expression implicitly coerced from 'Int?' to 'Any' on the print line. We see this because we are passing an option call to the print comment, which is expecting a non-optional value. To solve this issue, we can provide a value to use if our optional value happens to be nil; there is actually a really concise way to do this. The ?? operator can be can be applied after an optional value, and the value to the right of the operator will be used if the optional value is nil; this is called the nil coalescing operator:

print(numberOfFingersHeldUpByFinn ?? "Unknown")

At the end of the game, we want to store the number of fingers that Finn held up during the last round of the game. Since we know that we will play at least one round of the game, we know that there must be a value for the last number of fingers that were held up. Therefore, we declare the lastNumberOfFingersHeldUpByFinn variable as a non-optional Int:

let lastNumberOfFingersHeldUpByFinn: Int = numberOfFingersHeldUpByFinn! 

However, our numberOfFingersHeldUpByFinn variable is an optional Int. This is a problem for the compiler and the safeness and stability of our code as we would be applying a value that can be nil at runtime to a variable that is not allowed to be nil. If you remove ! from the preceding statement, that's what we will be doing, and the compiler will complain:

let lastNumberOfFingersHeldUpByFinn: Int = numberOfFingersHeldUpByFinn // Does not compile 

To get around this issue, we need to declare that although we initially declared this variable as optional, we know there is a value assigned to it, so we want to declare that this is now non-optional, which is denoted by the !.

In Swift terminology, we are unwrapping the optionality of the variable. Once it is unwrapped, and therefore non-optional, we can assign it to the lastNumberOfFingersHeldUpByFinn variable, which is also non optional.

Beware! Use of this forced unwrapping can be risky. When you forcibly unwrap an optional, as we just did, you are declaring to the compiler that you are sure that there will be a value in that variable at that point in the execution of the code. If for some reason you don't, and the variable is nil, you will get an error at runtime and your execution will terminate. If this code is running in an app, then the app will crash. We will see safer ways to unwrap an optional value in the later chapters.

Take the counting fingers game described earlier. Imagine that we ended the game before playing the first round:

// Start of the game 
var numberOfFingersHeldUpByFinn: Int?
// Hand behind his back
numberOfFingersHeldUpByFinn = nil
print(numberOfFingersHeldUpByFinn) // nil
// End of the game
let lastNumberOfFingersHeldUpByFinn: Int = numberOfFingersHeldUpByFinn!

This code will compile and run, but will crash at runtime because at the point that numberOfFingersHeldUpByFinn is assigned to lastNumberOfFingersHeldUpByFinn, the value of numberOfFingersHeldUpByFinn is nil.

There's more...

So far, we have seen non-optional variables, where a value of the correct type must be provided, and optional variables, where the value can either be the underlying type or nil. In a perfect world, this would be all we need. However, we may often find ourselves in the situation where we need to define a variable that we know should have a non-nil value, and, when it comes to be used, will have a value, but at the point of declaration, we don't know exactly what that value is. For these situations, we can declare a variable as an implicitly unwrapped optional (IUO) in Swift.

Run the following code in the playground:

var legalName: String!  
// At birth
legalName = nil
// At birth registration
legalName = "Alissa Jones"
// At enrolling in school
print(legalName)
// At enrolling in college
print(legalName)
// Registering Marriage
legalName = "Alissa Moon"
// When meeting new people
print(legalName)

In this example, we have a person's legal name, which is used at many points during their life, for instance, when registering for educational institutions. It can be changed, either by legal request or through marriage, and yet you would never expect someone's legal name to not exist. However, that is exactly what happens when someone is born! When a person is born (or initialized!), they don't have a legal name until their birth is registered. So, if we were trying to model this in code, a person's legal name could be represented as an IUO.

In code, we declare a variable to be an IUO by placing a ! sign after the type:

let legalName: String!  
IUOs present the same risk as forced unwrapping. You are promising that, although it's possible for the variable to be nil, when something tries to access it, a value will be there. If there isn't, the execution will terminate and your app will crash.

There is some subtlety to how IUOs behave when they are assigned to other variables and the type is inferred. Put the following into the playground, as it's best illustrated with code:

var input: Int! = 5 // Int! 
print(input) // 5
var output1 = input // Int?
print(output1 as Any) // Optional(5)
var output2 = input + 1 // Int
print(output2) // 5

When an IUO is assigned to a new variable, the compiler can't be sure that there is a non-nil value assigned. So, if an IUO is assigned to a new variable, as is the case with output1 here, the compiler plays it safe and infers that the type of this new variable is an optional. If, however, the value of the IUO has been unwrapped, then the compiler knows that it has a non-nil value, and will infer a non-optional type. When assigning output2 earlier, the value of the input is unwrapped in order to add 1 to it; therefore, the type of output2 is inferred to be the non-optional Int.

See also

You have been reading a chapter from
Swift 4 Programming Cookbook
Published in: Sep 2017
Publisher: Packt
ISBN-13: 9781786460899
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime