Book Image

Swift 4 Programming Cookbook

Book Image

Swift 4 Programming Cookbook

Overview of this book

Swift 4 is an exciting, multi-platform, general-purpose programming language. Being open source, modern and easy to use has made Swift one of the fastest growing programming languages. If you interested in exploring it, then this book is what you need. The book begins with an introduction to the basic building blocks of Swift 4, its syntax and the functionalities of Swift constructs. Then, introduces you to Apple's Xcode 9 IDE and Swift Playgrounds, which provide an ideal platform to write, execute, and debug the codes thus initiating your development process. Next, you'll learn to bundle variables into tuples, set order to your data with an array, store key-value pairs with dictionaries and you'll learn how to use the property observers. Later, explore the decision-making and control structures in Swift and learn how to handle errors in Swift 4. Then you'll, examine the advanced features of Swift, generics and operators, and then explore the functionalities outside of the standard library, provided by frameworks such as Foundation and UIKit. Also, you'll explore advanced features of Swift Playgrounds. At the end of the book, you'll learn server-side programming aspect of Swift 4 and see how to run Swift on Linux and then investigate Vapor, one of the most popular server-side frameworks for Swift.
Table of Contents (9 chapters)

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
// 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 

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
// At enrolling in college
// Registering Marriage
legalName = "Alissa Moon"
// When meeting new people

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