Book Image

Swift: Developing iOS Applications

By : Jon Hoffman, Andrew J Wagner, Giordano Scalzo
Book Image

Swift: Developing iOS Applications

By: Jon Hoffman, Andrew J Wagner, Giordano Scalzo

Overview of this book

The Swift––Developing iOS Applications course will take you on a journey to become an efficient iOS and OS X developer, with the latest trending topic in town. Right from the basics to the advanced level topics, this course would cover everything in detail. We’ll embark our journey by dividing the learning path into four modules. Each of these modules are a mini course in their own right; and as you complete each one, you’ll gain key skills and be ready for the material in the next module. The first module is like a step-by-step guide to programming in Swift 2. Each topic is separated into compressible sections that are full of practical examples and easy-to-understand explanations. Each section builds on the previous topics, so you can develop a proficient and comprehensive understanding of app development in Swift 2. By the end of this module, you’ll have a basic understanding of Swift 2 and its functionalities. The second module will be the an easy-to-follow guide filled with tutorials to show you how to build real-world apps. The difficulty and complexity level increases chapter by chapter. Each chapter is dedicated to build a new app, beginning from a basic and unstyled app through to a full 3D game. The last two chapters show you how to build a complete client-server e-commerce app right from scratch. By the end of these modules, you’ll be able to build well-designed apps, effectively use AutoLayout, develop videogames, and build server apps. The third and the last module of our course will take an example-based approach where each concept covered is supported by example code to not only give you a good understanding of the concept, but also to demonstrate how to properly implement it.
Table of Contents (6 chapters)
4
A. Biblography
5
Index

One of the coolest things about programming is the way that concepts build on each other. If you've never programmed anything before, even the most basic app can seem very complex. The reality is that, if you analyze everything going on in an app down to the ones and zeros flowing through the processor, it is incredibly complex. However, every aspect of using a computer is an abstraction. When you use an app, the complexity of the programming is being abstracted away for you. Learning to program is just going one level deeper in making a computer work for you.

As you learn the basic concepts behind programming, they will become second nature and this will free your mind to grasp even more complex concepts. When you first learn to read, sounding out each word is challenging. However, eventually, you reach a level where you glance at a word and you know the meaning instantaneously. This frees you up to start looking for deeper meaning from the text.

In this chapter, we will build up your knowledge of the building blocks of programming in Swift. Each of these building blocks is exciting on its own and they will become even more exciting as we start to see the possibilities they open up. No matter how complex programming might seem to you now, I guarantee that one day you will look back and marvel at how all of these concepts have become second nature.

In this chapter, we will cover:

Every programming language needs to name a piece of information so that it can be referenced later. This is the fundamental way in which code remains readable after it is written. Swift provides a number of core types that help you represent your information in a very comprehensible way.

It is often helpful to give a name to more complex information. We often have to deal with a collection of related information or a series of similar information like lists. Swift provides three main collection types called tuples, arrays, and dictionaries.

A dictionary is a collection of keys and values. Keys are used to store and look up specific values in the container. This container type is named after a word dictionary in which you can look up the definition of a word. In that real life example, the word would be the key and the definition would be the value. As an example, we can define a dictionary of television shows organized by their genre:

A dictionary looks similar to an array but each key and value is separated by a colon (:). Note that Swift is pretty forgiving with how whitespace is used. The array could be defined with each element on its own line and the dictionary could be defined with every element on a single line. It is up to you to use whitespace to make your code as readable as possible.

With the dictionary defined as shown above, you would get the value Modern Family if you looked up the key Comedy. You access a value in code similar to how you would in an array but, instead of providing an index in the square brackets, you provide the key:

You can define an empty dictionary in a similar way to an empty array but with a dictionary you must also include a colon between the brackets: [:].

Adding a value to a dictionary is similar to retrieving a value but you use the assignment operator (=):

As a bonus, this can also be used to change the value for an existing key.

You might have noticed that all of my variable and constant names begin with a lower case letter and each subsequent word starts with a capital letter. This is called camel case and it is the widely accepted way of writing variable and constant names. Following this convention makes it easier for other programmers to understand your code.

Now that we know about Swift's basic containers, let's explore what they are in a little more detail.

Swift is a strongly typed language, which means that every constant and variable is defined with a specific type. Only values of matching types can be assigned to them. So far, we have taken advantage of a feature of Swift called Type Inference. This means that the code does not have to explicitly declare a type if it can be inferred from the value being assigned to it during the declaration.

Without Type Inference, the name variable declaration from before would be written as follows:

This code is explicitly declaring name as the type String with the value Sarah. A constant or variable's type can be specified by adding a colon (:) and a type after its name.

A string is defined by a series of characters. This is perfect for storing text, as in our name example. The reason that we don't need to specify the type is that Sarah is a string literal. Text surrounded by quotation marks is a string literal and can be inferred to be of the type String. That means that name must be of the type String if you make its initial value Sarah.

Similarly, if we had not used type inference for our other variable declarations, they would look like this:

Double is a numeric type that can store decimal numbers. An array's type is declared by putting the type of element it stores in square brackets. Finally, a dictionary's type is defined in the form [KeyType:ValueType]. All of these types can be inferred because each of them is assigned to a value that has an inferable type.

The code is much cleaner and easier to understand if we leave the types out as the original examples showed. Just keep in mind that these types are always implied to be there, even if they are not written explicitly. If we tried to assign a number to the name variable, we would get an error, as shown:

Swift's type system

Here, we are trying to assign a number, specifically an Int, to a variable that was inferred to be a String. Swift does not allow that.

When dealing with inferred types, it is extremely useful to ask Xcode what type a variable is inferred to be. You can do this by holding down the Option key on your keyboard and clicking on the variable name. This will display a pop-up that looks like this:

Swift's type system

As was expected, the variable was indeed inferred to be of the type String.

Types are an integral part of Swift. They are one of the major reasons that Swift is so safe as a programming language. They help the compiler learn more about your code and, because of that, the compiler can warn you about bugs automatically without even running your code.

It is very useful to write output to a log so that you can trace the behavior of code. As a codebase grows in complexity, it gets hard to follow the order in which things happen and exactly what the data looks like as it flows through the code. Playgrounds help a lot with this but it is not always enough.

In Swift, this process is called printing to the console. To do this, you use something called print. It is used by writing print followed by text surrounded by parentheses. For example, to print Hello World! to the console, the code would look like this:

If you put that code in a playground, you would see Hello World! written in the results pane. However, this is not truly the console. To view the console, you can go to View | Debug Area | Show Debug Area. A new view will appear at the bottom of the window and it will contain all text the code has printed to the console:

Printing to the console

Not only can you print static text to the console, you can also print out any variable. For example, if you wanted to print out the name variable, you would write:

You can even use a feature of Swift called string interpolation to insert variables into a string, like this:

At any point in a string literal, even when not printing, you can insert the results of the code by surrounding the code with \( and ). Normally this would be the name of a variable but it could be any code that returns a value.

Printing to the console is even more useful when we start using more complex code.

A program wouldn't be very useful if it were a single fixed list of commands that always did the same thing. With a single code path, a calculator app would only be able to perform one operation. There are a number of things we can do to make an app more powerful and collect the data to make decisions as to what to do next.

The most basic way to control the flow of a program is to specify code that should only be executed if a certain condition is met. In Swift, we do that with an if statement. Let's look at an example:

Semantically, the preceding code reads; if the number of invitees is greater then 20, print 'Too many people invited". This example only executes one line of code if the condition is true, but you can put as much code as you like inside the curly brackets ({}).

Anything that can be evaluated as either true or false can be used in an if statement. You can then chain multiple conditions together using an else if and/or an else:

Each condition is checked from top to bottom until a condition is satisfied. At that point, the code block is executed and the remaining conditions are skipped, including the final else block.

As an exercise, I recommend adding an additional scenario to the preceding code in which, if there were exactly zero invitees, it would print "One is the loneliest number". You can test out your code by adjusting how many invitees you add to the invitees declaration. Remember that the order of the conditions is very important.

As useful as conditionals are, they can become very verbose if you have a lot of them chained together. To solve this type of problem, there is another control structure called a switch.

A switch is a more expressive way of writing a series of if statements. A direct translation of the example from the conditionals section would look like this:

A switch consists of a value and a list of conditions for that value with the code to execute if the condition is true. The value to be tested is written immediately after the switch command and all of the conditions are contained in curly brackets ({}). Each condition is called a case. Using that terminology, the semantics of the preceding code is "Considering the number of invitees, in the case that it is greater than 20, print "Too many people invited", otherwise, in the case that it is less than or equal to three, print "Too many people invited", otherwise, by default print "Just right".

This works by creating a temporary constant x that is given the value that the switch is testing. It then performs a test on x. If the condition passes, it executes the code for that case and then exits the switch.

Just like in conditionals, each case is only considered if all of the previous cases are not satisfied. Unlike conditionals, all the cases need to be exhaustive. That means that you need to have a case for every possible value that the variable being passed in could be. For example, invitees.count is an integer, so it could theoretically be any value from negative infinity to positive infinity.

The most common way to handle that is by using a default case as designated by the default keyword. Sometimes, you don't actually want to do anything in the default case, or possibly even in a specific case. For that, you can use the break keyword, as shown here:

Note that the default case must always be the last one.

We have seen so far that switches are nice because they enforce the condition of being exhaustive. This is great for letting the compiler catch bugs for you. However, switches can also be much more concise. We can rewrite the preceding code like this:

Here, we have described each case as a range of possible values. The first case includes all of the values between and including 0 and 3. This is way more expressive than using a where clause. This example also shows a rethinking of the logic. Instead of having a case specific for values over 20, we have cases for the closed ranges that we know and then capture everything for the case above 20 in the default case. Note that this version of the code does not properly handle the situation in which the count might be negative, whereas the original version did. In this version, if the count were -1, it would fall all the way through to the default case and print out "Too many people invited". For this use case, it is fine because the count of an array can never be negative.

Switches don't only work with numbers. They are great for performing any type of test:

This code shows some other interesting features of switches. The first case is actually made up of two separate conditions. Each case can have any number of conditions separated by commas (,). This is useful when you have multiple cases that you want to use the same code for.

The second case uses a custom test on the name to see if it starts with the letter A. This is great for demonstrating the way in which switches are executed. Even though the string Amy would satisfy the second condition, this code would only print, Amy is an honored guest because the other cases are not evaluated once the first case is satisfied. For now, don't worry if you don't understand completely how hasPrefix works.

Lastly, the second case uses the fallthrough keyword. This tells the program to execute the code in the following case. Importantly, this bypasses the next case's condition; it does not matter if the value passes the condition, the code is still executed.

To make sure that you understand how a switch is executed, put the following code into a playground and try to predict what will be printed out with various names:

Some good names to try are Andrew, Amy, and Jamison.

Now we have full control over which code we want executed in which circumstances. However, a program often requires that we execute the same code more than once. For example, if we want to perform an operation on every element in an array, it would not be viable to copy and paste a bunch of code. Instead, we can use control structures called loops.

There are many different types of loops but all of them execute the same code repeatedly until a condition is no longer true. The most basic type of loop is called a while loop:

A while loop consists of a condition to test and code to be run until that condition fails. In the preceding example, we have looped through every element in the invitees array. We used the variable index to track which invitee we were currently on. To move to the next index, we used a new operator += which added one to the existing value. This is the same as writing index = index + 1.

There are two important things to note about this loop. Firstly, our index starts at 0, not 1, and it goes on until it is less than the number of invitees, not less than or equal to them. This is because, if you remember, array indexes start at 0. If we started at 1 we would miss the first element and, if we included invitees.count, the code would crash because it would try to access an element beyond the end of the array. Always remember: the last element of an array is at the index one less than the count.

The other thing to note is that, if we were to forget to include index+=1 in the loop, we would have an infinite loop. The loop would continue to run forever because index would never go beyond invitees.count.

This pattern of wanting to loop through a list is so common that there is a more concise and safe loop called a for-in loop:

Now this is getting pretty cool. We no longer have to worry about indexes. There is no risk of accidentally starting at 1 or going past the end. Also, we get to give our own name to the specific element as we go through the array. One thing to note is that we did not declare the invitee variable with let or var. This is particular to a for-in loop because the constant used there is newly declared each time through the loop.

for-in loops are great for looping through different types of containers. They can also be used to loop through a dictionary, as shown:

In this case, we get access to both the key and the value of the dictionary. This should look familiar because (genre, show) is actually a tuple used for each iteration through the loop. It may be confusing to determine whether or not you have a single value from a for-in loop like arrays or a tuple like dictionaries. At this point, it would be best for you to remember just these two common cases. The underlying reasons will become clear when we start talking about sequences in Chapter 6, Make Swift Work For You – Protocols and Generics.

Another feature of for-in loops is the ability to only loop through elements that pass a given test. You could achieve this with an if statement but Swift provides a more concise way of writing it using the where keyword:

Now, the loop will only be run for each of the invitees that start with the letter A.

These loops are great but sometimes we need access to the index we are currently on and, at other times, we may want to loop through a set of numbers without an array. To do this, we can use a range similar to a Switch, as shown:

This code runs the loop using the variable index from the value 0 up to but not including invitees.count. There are actually two types of ranges. This one is called a half open range because it does not include the last value. The other type of range, which we saw with switches, is called a closed range:

The closed range includes the last value so that the loop will print out every number starting with 1 and ending with 10.

All loops have two special keywords that let you modify their behavior, which are called continue and break. continue is used to skip the rest of the loop and move back to the condition to see whether or not the loop should be run again. For example, if we didn't want to print out invitees whose name began with A, we would use the following:

If the condition invitee.hasPrefix("A") were satisfied, the continue command would be run and it would skip the rest of the loop, moving onto the next invitee. Because of this, only invitees not starting with A would be printed.

The break keyword is used to immediately exit a loop:

As soon as a break is encountered, the execution jumps to after the loop. In this case, it jumps to the final line.

Loops are great for dealing with variable amounts of data, like our list of invitees. When writing your code, you probably won't know how many people will be in that list. Using a loop gives you the flexibility to handle a list of any length.

As an exercise, I recommend you try writing a loop to find the sum of all the multiples of 3 under 10,000. You should get 16,668,333.

Loops are also a great way of reusing code without duplicating it but they are just the first step towards quality code reuse. Next, we will talk about functions, which opens up a whole new world of writing understandable and reusable code.

Conditionals

The most

basic way to control the flow of a program is to specify code that should only be executed if a certain condition is met. In Swift, we do that with an if statement. Let's look at an example:

Semantically, the preceding code reads; if the number of invitees is greater then 20, print 'Too many people invited". This example only executes one line of code if the condition is true, but you can put as much code as you like inside the curly brackets ({}).

Anything that can be evaluated as either true or false can be used in an if statement. You can then chain multiple conditions together using an else if and/or an else:

Each condition is checked from top to bottom until a condition is satisfied. At that point, the code block is executed and the remaining conditions are skipped, including the final else block.

As an exercise, I recommend adding an additional scenario to the preceding code in which, if there were exactly zero invitees, it would print "One is the loneliest number". You can test out your code by adjusting how many invitees you add to the invitees declaration. Remember that the order of the conditions is very important.

As useful as conditionals are, they can become very verbose if you have a lot of them chained together. To solve this type of problem, there is another control structure called a switch.

A switch is a more expressive way of writing a series of if statements. A direct translation of the example from the conditionals section would look like this:

A switch consists of a value and a list of conditions for that value with the code to execute if the condition is true. The value to be tested is written immediately after the switch command and all of the conditions are contained in curly brackets ({}). Each condition is called a case. Using that terminology, the semantics of the preceding code is "Considering the number of invitees, in the case that it is greater than 20, print "Too many people invited", otherwise, in the case that it is less than or equal to three, print "Too many people invited", otherwise, by default print "Just right".

This works by creating a temporary constant x that is given the value that the switch is testing. It then performs a test on x. If the condition passes, it executes the code for that case and then exits the switch.

Just like in conditionals, each case is only considered if all of the previous cases are not satisfied. Unlike conditionals, all the cases need to be exhaustive. That means that you need to have a case for every possible value that the variable being passed in could be. For example, invitees.count is an integer, so it could theoretically be any value from negative infinity to positive infinity.

The most common way to handle that is by using a default case as designated by the default keyword. Sometimes, you don't actually want to do anything in the default case, or possibly even in a specific case. For that, you can use the break keyword, as shown here:

Note that the default case must always be the last one.

We have seen so far that switches are nice because they enforce the condition of being exhaustive. This is great for letting the compiler catch bugs for you. However, switches can also be much more concise. We can rewrite the preceding code like this:

Here, we have described each case as a range of possible values. The first case includes all of the values between and including 0 and 3. This is way more expressive than using a where clause. This example also shows a rethinking of the logic. Instead of having a case specific for values over 20, we have cases for the closed ranges that we know and then capture everything for the case above 20 in the default case. Note that this version of the code does not properly handle the situation in which the count might be negative, whereas the original version did. In this version, if the count were -1, it would fall all the way through to the default case and print out "Too many people invited". For this use case, it is fine because the count of an array can never be negative.

Switches don't only work with numbers. They are great for performing any type of test:

This code shows some other interesting features of switches. The first case is actually made up of two separate conditions. Each case can have any number of conditions separated by commas (,). This is useful when you have multiple cases that you want to use the same code for.

The second case uses a custom test on the name to see if it starts with the letter A. This is great for demonstrating the way in which switches are executed. Even though the string Amy would satisfy the second condition, this code would only print, Amy is an honored guest because the other cases are not evaluated once the first case is satisfied. For now, don't worry if you don't understand completely how hasPrefix works.

Lastly, the second case uses the fallthrough keyword. This tells the program to execute the code in the following case. Importantly, this bypasses the next case's condition; it does not matter if the value passes the condition, the code is still executed.

To make sure that you understand how a switch is executed, put the following code into a playground and try to predict what will be printed out with various names:

Some good names to try are Andrew, Amy, and Jamison.

Now we have full control over which code we want executed in which circumstances. However, a program often requires that we execute the same code more than once. For example, if we want to perform an operation on every element in an array, it would not be viable to copy and paste a bunch of code. Instead, we can use control structures called loops.

There are many different types of loops but all of them execute the same code repeatedly until a condition is no longer true. The most basic type of loop is called a while loop:

A while loop consists of a condition to test and code to be run until that condition fails. In the preceding example, we have looped through every element in the invitees array. We used the variable index to track which invitee we were currently on. To move to the next index, we used a new operator += which added one to the existing value. This is the same as writing index = index + 1.

There are two important things to note about this loop. Firstly, our index starts at 0, not 1, and it goes on until it is less than the number of invitees, not less than or equal to them. This is because, if you remember, array indexes start at 0. If we started at 1 we would miss the first element and, if we included invitees.count, the code would crash because it would try to access an element beyond the end of the array. Always remember: the last element of an array is at the index one less than the count.

The other thing to note is that, if we were to forget to include index+=1 in the loop, we would have an infinite loop. The loop would continue to run forever because index would never go beyond invitees.count.

This pattern of wanting to loop through a list is so common that there is a more concise and safe loop called a for-in loop:

Now this is getting pretty cool. We no longer have to worry about indexes. There is no risk of accidentally starting at 1 or going past the end. Also, we get to give our own name to the specific element as we go through the array. One thing to note is that we did not declare the invitee variable with let or var. This is particular to a for-in loop because the constant used there is newly declared each time through the loop.

for-in loops are great for looping through different types of containers. They can also be used to loop through a dictionary, as shown:

In this case, we get access to both the key and the value of the dictionary. This should look familiar because (genre, show) is actually a tuple used for each iteration through the loop. It may be confusing to determine whether or not you have a single value from a for-in loop like arrays or a tuple like dictionaries. At this point, it would be best for you to remember just these two common cases. The underlying reasons will become clear when we start talking about sequences in Chapter 6, Make Swift Work For You – Protocols and Generics.

Another feature of for-in loops is the ability to only loop through elements that pass a given test. You could achieve this with an if statement but Swift provides a more concise way of writing it using the where keyword:

Now, the loop will only be run for each of the invitees that start with the letter A.

These loops are great but sometimes we need access to the index we are currently on and, at other times, we may want to loop through a set of numbers without an array. To do this, we can use a range similar to a Switch, as shown:

This code runs the loop using the variable index from the value 0 up to but not including invitees.count. There are actually two types of ranges. This one is called a half open range because it does not include the last value. The other type of range, which we saw with switches, is called a closed range:

The closed range includes the last value so that the loop will print out every number starting with 1 and ending with 10.

All loops have two special keywords that let you modify their behavior, which are called continue and break. continue is used to skip the rest of the loop and move back to the condition to see whether or not the loop should be run again. For example, if we didn't want to print out invitees whose name began with A, we would use the following:

If the condition invitee.hasPrefix("A") were satisfied, the continue command would be run and it would skip the rest of the loop, moving onto the next invitee. Because of this, only invitees not starting with A would be printed.

The break keyword is used to immediately exit a loop:

As soon as a break is encountered, the execution jumps to after the loop. In this case, it jumps to the final line.

Loops are great for dealing with variable amounts of data, like our list of invitees. When writing your code, you probably won't know how many people will be in that list. Using a loop gives you the flexibility to handle a list of any length.

As an exercise, I recommend you try writing a loop to find the sum of all the multiples of 3 under 10,000. You should get 16,668,333.

Loops are also a great way of reusing code without duplicating it but they are just the first step towards quality code reuse. Next, we will talk about functions, which opens up a whole new world of writing understandable and reusable code.

Switches

A

switch is a more expressive way of writing a series of if statements. A direct translation of the example from the conditionals section would look like this:

A switch consists of a value and a list of conditions for that value with the code to execute if the condition is true. The value to be tested is written immediately after the switch command and all of the conditions are contained in curly brackets ({}). Each condition is called a case. Using that terminology, the semantics of the preceding code is "Considering the number of invitees, in the case that it is greater than 20, print "Too many people invited", otherwise, in the case that it is less than or equal to three, print "Too many people invited", otherwise, by default print "Just right".

This works by creating a temporary constant x that is given the value that the switch is testing. It then performs a test on x. If the condition passes, it executes the code for that case and then exits the switch.

Just like in conditionals, each case is only considered if all of the previous cases are not satisfied. Unlike conditionals, all the cases need to be exhaustive. That means that you need to have a case for every possible value that the variable being passed in could be. For example, invitees.count is an integer, so it could theoretically be any value from negative infinity to positive infinity.

The most common way to handle that is by using a default case as designated by the default keyword. Sometimes, you don't actually want to do anything in the default case, or possibly even in a specific case. For that, you can use the break keyword, as shown here:

Note that the default case must always be the last one.

We have seen so far that switches are nice because they enforce the condition of being exhaustive. This is great for letting the compiler catch bugs for you. However, switches can also be much more concise. We can rewrite the preceding code like this:

Here, we have described each case as a range of possible values. The first case includes all of the values between and including 0 and 3. This is way more expressive than using a where clause. This example also shows a rethinking of the logic. Instead of having a case specific for values over 20, we have cases for the closed ranges that we know and then capture everything for the case above 20 in the default case. Note that this version of the code does not properly handle the situation in which the count might be negative, whereas the original version did. In this version, if the count were -1, it would fall all the way through to the default case and print out "Too many people invited". For this use case, it is fine because the count of an array can never be negative.

Switches don't only work with numbers. They are great for performing any type of test:

This code shows some other interesting features of switches. The first case is actually made up of two separate conditions. Each case can have any number of conditions separated by commas (,). This is useful when you have multiple cases that you want to use the same code for.

The second case uses a custom test on the name to see if it starts with the letter A. This is great for demonstrating the way in which switches are executed. Even though the string Amy would satisfy the second condition, this code would only print, Amy is an honored guest because the other cases are not evaluated once the first case is satisfied. For now, don't worry if you don't understand completely how hasPrefix works.

Lastly, the second case uses the fallthrough keyword. This tells the program to execute the code in the following case. Importantly, this bypasses the next case's condition; it does not matter if the value passes the condition, the code is still executed.

To make sure that you understand how a switch is executed, put the following code into a playground and try to predict what will be printed out with various names:

Some good names to try are Andrew, Amy, and Jamison.

Now we have full control over which code we want executed in which circumstances. However, a program often requires that we execute the same code more than once. For example, if we want to perform an operation on every element in an array, it would not be viable to copy and paste a bunch of code. Instead, we can use control structures called loops.

There are many different types of loops but all of them execute the same code repeatedly until a condition is no longer true. The most basic type of loop is called a while loop:

A while loop consists of a condition to test and code to be run until that condition fails. In the preceding example, we have looped through every element in the invitees array. We used the variable index to track which invitee we were currently on. To move to the next index, we used a new operator += which added one to the existing value. This is the same as writing index = index + 1.

There are two important things to note about this loop. Firstly, our index starts at 0, not 1, and it goes on until it is less than the number of invitees, not less than or equal to them. This is because, if you remember, array indexes start at 0. If we started at 1 we would miss the first element and, if we included invitees.count, the code would crash because it would try to access an element beyond the end of the array. Always remember: the last element of an array is at the index one less than the count.

The other thing to note is that, if we were to forget to include index+=1 in the loop, we would have an infinite loop. The loop would continue to run forever because index would never go beyond invitees.count.

This pattern of wanting to loop through a list is so common that there is a more concise and safe loop called a for-in loop:

Now this is getting pretty cool. We no longer have to worry about indexes. There is no risk of accidentally starting at 1 or going past the end. Also, we get to give our own name to the specific element as we go through the array. One thing to note is that we did not declare the invitee variable with let or var. This is particular to a for-in loop because the constant used there is newly declared each time through the loop.

for-in loops are great for looping through different types of containers. They can also be used to loop through a dictionary, as shown:

In this case, we get access to both the key and the value of the dictionary. This should look familiar because (genre, show) is actually a tuple used for each iteration through the loop. It may be confusing to determine whether or not you have a single value from a for-in loop like arrays or a tuple like dictionaries. At this point, it would be best for you to remember just these two common cases. The underlying reasons will become clear when we start talking about sequences in Chapter 6, Make Swift Work For You – Protocols and Generics.

Another feature of for-in loops is the ability to only loop through elements that pass a given test. You could achieve this with an if statement but Swift provides a more concise way of writing it using the where keyword:

Now, the loop will only be run for each of the invitees that start with the letter A.

These loops are great but sometimes we need access to the index we are currently on and, at other times, we may want to loop through a set of numbers without an array. To do this, we can use a range similar to a Switch, as shown:

This code runs the loop using the variable index from the value 0 up to but not including invitees.count. There are actually two types of ranges. This one is called a half open range because it does not include the last value. The other type of range, which we saw with switches, is called a closed range:

The closed range includes the last value so that the loop will print out every number starting with 1 and ending with 10.

All loops have two special keywords that let you modify their behavior, which are called continue and break. continue is used to skip the rest of the loop and move back to the condition to see whether or not the loop should be run again. For example, if we didn't want to print out invitees whose name began with A, we would use the following:

If the condition invitee.hasPrefix("A") were satisfied, the continue command would be run and it would skip the rest of the loop, moving onto the next invitee. Because of this, only invitees not starting with A would be printed.

The break keyword is used to immediately exit a loop:

As soon as a break is encountered, the execution jumps to after the loop. In this case, it jumps to the final line.

Loops are great for dealing with variable amounts of data, like our list of invitees. When writing your code, you probably won't know how many people will be in that list. Using a loop gives you the flexibility to handle a list of any length.

As an exercise, I recommend you try writing a loop to find the sum of all the multiples of 3 under 10,000. You should get 16,668,333.

Loops are also a great way of reusing code without duplicating it but they are just the first step towards quality code reuse. Next, we will talk about functions, which opens up a whole new world of writing understandable and reusable code.

Loops

There

are many different types of loops but all of them execute the same code repeatedly until a condition is no longer true. The most basic type of loop is called a while loop:

A while loop consists of a condition to test and code to be run until that condition fails. In the preceding example, we have looped through every element in the invitees array. We used the variable index to track which invitee we were currently on. To move to the next index, we used a new operator += which added one to the existing value. This is the same as writing index = index + 1.

There are two important things to note about this loop. Firstly, our index starts at 0, not 1, and it goes on until it is less than the number of invitees, not less than or equal to them. This is because, if you remember, array indexes start at 0. If we started at 1 we would miss the first element and, if we included invitees.count, the code would crash because it would try to access an element beyond the end of the array. Always remember: the last element of an array is at the index one less than the count.

The other thing to note is that, if we were to forget to include index+=1 in the loop, we would have an infinite loop. The loop would continue to run forever because index would never go beyond invitees.count.

This pattern of wanting to loop through a list is so common that there is a more concise and safe loop called a for-in loop:

Now this is getting pretty cool. We no longer have to worry about indexes. There is no risk of accidentally starting at 1 or going past the end. Also, we get to give our own name to the specific element as we go through the array. One thing to note is that we did not declare the invitee variable with let or var. This is particular to a for-in loop because the constant used there is newly declared each time through the loop.

for-in loops are great for looping through different types of containers. They can also be used to loop through a dictionary, as shown:

In this case, we get access to both the key and the value of the dictionary. This should look familiar because (genre, show) is actually a tuple used for each iteration through the loop. It may be confusing to determine whether or not you have a single value from a for-in loop like arrays or a tuple like dictionaries. At this point, it would be best for you to remember just these two common cases. The underlying reasons will become clear when we start talking about sequences in Chapter 6, Make Swift Work For You – Protocols and Generics.

Another feature of for-in loops is the ability to only loop through elements that pass a given test. You could achieve this with an if statement but Swift provides a more concise way of writing it using the where keyword:

Now, the loop will only be run for each of the invitees that start with the letter A.

These loops are great but sometimes we need access to the index we are currently on and, at other times, we may want to loop through a set of numbers without an array. To do this, we can use a range similar to a Switch, as shown:

This code runs the loop using the variable index from the value 0 up to but not including invitees.count. There are actually two types of ranges. This one is called a half open range because it does not include the last value. The other type of range, which we saw with switches, is called a closed range:

The closed range includes the last value so that the loop will print out every number starting with 1 and ending with 10.

All loops have two special keywords that let you modify their behavior, which are called continue and break. continue is used to skip the rest of the loop and move back to the condition to see whether or not the loop should be run again. For example, if we didn't want to print out invitees whose name began with A, we would use the following:

If the condition invitee.hasPrefix("A") were satisfied, the continue command would be run and it would skip the rest of the loop, moving onto the next invitee. Because of this, only invitees not starting with A would be printed.

The break keyword is used to immediately exit a loop:

As soon as a break is encountered, the execution jumps to after the loop. In this case, it jumps to the final line.

Loops are great for dealing with variable amounts of data, like our list of invitees. When writing your code, you probably won't know how many people will be in that list. Using a loop gives you the flexibility to handle a list of any length.

As an exercise, I recommend you try writing a loop to find the sum of all the multiples of 3 under 10,000. You should get 16,668,333.

Loops are also a great way of reusing code without duplicating it but they are just the first step towards quality code reuse. Next, we will talk about functions, which opens up a whole new world of writing understandable and reusable code.

All of the code we have explored so far is very linear down the file. Each line is processed one at a time and then the program moves onto the next. This is one of the great things about programming: everything the program does can be predicted by stepping through the program yourself mentally, one line at a time.

However, as your program gets larger, you will notice that there are places that reuse very similar or identical code that you cannot reuse by using loops. Moreover, the more code you write, the harder it becomes to know exactly what it is doing. Code comments can help with that but there is an even better solution to both of these problems and they're called functions. A function is essentially a named collection of code that can be executed and reused by using that name.

There are various different types of functions but each builds on the previous type.

The most basic type of function simply has a name with some static code to be executed later. Let's look at a simple example. The following code defines a function named sayHello:

Functions are defined using the keyword func followed by a name and parentheses (()). The code to be run in the function is surrounded by curly brackets ({}). Just like in loops, a function can consist of any number of lines of code.

From our knowledge of printing, we know that this function will print out the text Hello World!. However, when will it do that? The terminology used for telling a function to execute is "calling a function." You call a function by using its name followed by parentheses (()):

This is a very simple function that is not that useful but we can already see some pretty great benefits of functions. In reality, what happens when you call this function is that the execution moves into the function and, when it has finished executing every line of the function, it exits out and continues on from where the function was called. However, as programmers, we are often not concerned with what is happening inside a function unless something has gone wrong. If functions are named well, they tell you what they will do and that is all you need to know to follow the rest of the code. In fact, well-named functions can almost always take the place of comments in your code. This really reduces clutter without harming the legibility of your code.

The other advantage this function has over using print directly is that the code becomes more maintainable. If you use print in multiple places in your code and then change your mind about how you want to say Hello, you have to change a lot of code. However, if you use a function like the one above, you can easily change how it says Hello by changing the function and it will then be changed in each place you use that function.

You may have noticed some similarity in how we have named our sayHello function and how we used print. This is because print is a function that is built into Swift itself. There is complex code in the print function that makes printing to the console possible and accessible to all programmers. But hey, print is able to take in a value and do something with it, how do we write a function like that? The answer is: parameters.

The type of value to be returned from a function is defined after the end of all of the parameters separated by an arrow ->. Let's write a function that takes a list of invitees and one other person to add to the list. If there are spots available, the function adds the person to the list and returns the new version. If there are no spots available, it just returns the original list, as shown here:

In this function, we tested the number of names on the invitee list and, if it was greater than 20, we returned the same list as was passed in to the invitees parameter. Note that return is used in a function in a similar way to break in a loop. As soon as the program executes a line that returns, it exits the function and provides that value to the calling code. So, the final return line is only run if the if statement does not pass. It then adds the newinvitee parameter to the list and returns that to the calling code.

You would call this function like so:

It is important to note that we must assign list to the value returned from our function because it is possible that the new value will be changed by the function. If we did not do this, nothing would happen to the list.

If you try typing this code into a playground, you will notice something very cool. As you begin typing the name of the function, you will see a small pop-up that suggests the name of the function you might want to type, as shown:

Functions that return values

You can use the arrow keys to move up and down the list to select the function you want to type and then press the Tab key to make Xcode finish typing the function for you. Not only that, but it highlights the first parameter so that you can immediately start typing what you want to pass in. When you are done defining the first parameter, you can press Tab again to move on to the next parameter. This greatly increases the speed with which you can write your code.

This is a pretty well-named function because it is clear what it does. However, we can give it a more natural and expressive name by making it read more like a sentence:

This is a great feature of Swift that allows you to have a function called with named parameters. We can do this by giving the second parameter two names, separated by a space. The first name is the one to be used when calling the function, otherwise referred to as the external name. The second name is the one to be used when referring to the constant being passed in from within the function, otherwise referred to as the internal name. As an exercise, try to change the function so that it uses the same external and internal names and see what Xcode suggests. For more of a challenge, write a function that takes a list of invitees and an index for a specific invitee to write a message to ask them to just bring themselves. For example, it would print Sarah, just bring yourself for the index 0 in the preceding list.

Sometimes we write functions where there is a parameter that commonly has the same value. It would be great if we could provide a value for a parameter to be used if the caller did not override that value. Swift has a feature for this called default arguments. To define a default value for an argument, you simply add an equal sign after the argument, followed by the value. We can add a default argument to the sayHelloToName: function, as follows:

This means that we can now call this function with or without specifying a name:

When using default arguments, the order of the arguments becomes unimportant. We can add default arguments to our addInvitee:ifPossibleToList: function and then call it with any combination or order of arguments:

Clearly, the call still reads much better when it is written in the same order but not all functions are designed in that way. The most important part of this feature is that you can specify only the arguments that you want to be different from the defaults.

The last feature of functions that we are going to discuss is another type of conditional called a guard statement. We have not discussed it until now because it doesn't make much sense unless it is used in a function or loop. A guard statement acts in a similar way to an if statement but the compiler forces you to provide an else condition that must exit from the function, loop, or switch case. Let's rework our addInvitee:ifPossibleToList: function to see what it looks like:

Semantically, the guard statement instructs us to ensure that the number of invitees is less than 20 or else return the original list. This is a reversal of the logic we used before, when we returned the original list if there were 20 or more invitees. This logic actually makes more sense because we are stipulating a prerequisite and providing a failure path. The other nice thing about using the guard statement is that we can't forget to return out of the else condition. If we do, the compiler will give us an error.

It is important to note that guard statements do not have a block of code that is executed if it passes. Only an else condition can be specified with the assumption that any code you want to run for the passing condition will simply come after the statement. This is safe only because the compiler forces the else condition to exit the function and, in turn, ensures that the code after the statement will not run.

Overall, guard statements are a great way of defining preconditions to a function or loop without having to indent your code for the passing case. This is not a big deal for us yet but, if you have lots of preconditions, it often becomes cumbersome to indent the code far enough to handle them.

Basic functions

The most

basic type of function simply has a name with some static code to be executed later. Let's look at a simple example. The following code defines a function named sayHello:

Functions are defined using the keyword func followed by a name and parentheses (()). The code to be run in the function is surrounded by curly brackets ({}). Just like in loops, a function can consist of any number of lines of code.

From our knowledge of printing, we know that this function will print out the text Hello World!. However, when will it do that? The terminology used for telling a function to execute is "calling a function." You call a function by using its name followed by parentheses (()):

This is a very simple function that is not that useful but we can already see some pretty great benefits of functions. In reality, what happens when you call this function is that the execution moves into the function and, when it has finished executing every line of the function, it exits out and continues on from where the function was called. However, as programmers, we are often not concerned with what is happening inside a function unless something has gone wrong. If functions are named well, they tell you what they will do and that is all you need to know to follow the rest of the code. In fact, well-named functions can almost always take the place of comments in your code. This really reduces clutter without harming the legibility of your code.

The other advantage this function has over using print directly is that the code becomes more maintainable. If you use print in multiple places in your code and then change your mind about how you want to say Hello, you have to change a lot of code. However, if you use a function like the one above, you can easily change how it says Hello by changing the function and it will then be changed in each place you use that function.

You may have noticed some similarity in how we have named our sayHello function and how we used print. This is because print is a function that is built into Swift itself. There is complex code in the print function that makes printing to the console possible and accessible to all programmers. But hey, print is able to take in a value and do something with it, how do we write a function like that? The answer is: parameters.

The type of value to be returned from a function is defined after the end of all of the parameters separated by an arrow ->. Let's write a function that takes a list of invitees and one other person to add to the list. If there are spots available, the function adds the person to the list and returns the new version. If there are no spots available, it just returns the original list, as shown here:

In this function, we tested the number of names on the invitee list and, if it was greater than 20, we returned the same list as was passed in to the invitees parameter. Note that return is used in a function in a similar way to break in a loop. As soon as the program executes a line that returns, it exits the function and provides that value to the calling code. So, the final return line is only run if the if statement does not pass. It then adds the newinvitee parameter to the list and returns that to the calling code.

You would call this function like so:

It is important to note that we must assign list to the value returned from our function because it is possible that the new value will be changed by the function. If we did not do this, nothing would happen to the list.

If you try typing this code into a playground, you will notice something very cool. As you begin typing the name of the function, you will see a small pop-up that suggests the name of the function you might want to type, as shown:

Functions that return values

You can use the arrow keys to move up and down the list to select the function you want to type and then press the Tab key to make Xcode finish typing the function for you. Not only that, but it highlights the first parameter so that you can immediately start typing what you want to pass in. When you are done defining the first parameter, you can press Tab again to move on to the next parameter. This greatly increases the speed with which you can write your code.

This is a pretty well-named function because it is clear what it does. However, we can give it a more natural and expressive name by making it read more like a sentence:

This is a great feature of Swift that allows you to have a function called with named parameters. We can do this by giving the second parameter two names, separated by a space. The first name is the one to be used when calling the function, otherwise referred to as the external name. The second name is the one to be used when referring to the constant being passed in from within the function, otherwise referred to as the internal name. As an exercise, try to change the function so that it uses the same external and internal names and see what Xcode suggests. For more of a challenge, write a function that takes a list of invitees and an index for a specific invitee to write a message to ask them to just bring themselves. For example, it would print Sarah, just bring yourself for the index 0 in the preceding list.

Sometimes we write functions where there is a parameter that commonly has the same value. It would be great if we could provide a value for a parameter to be used if the caller did not override that value. Swift has a feature for this called default arguments. To define a default value for an argument, you simply add an equal sign after the argument, followed by the value. We can add a default argument to the sayHelloToName: function, as follows:

This means that we can now call this function with or without specifying a name:

When using default arguments, the order of the arguments becomes unimportant. We can add default arguments to our addInvitee:ifPossibleToList: function and then call it with any combination or order of arguments:

Clearly, the call still reads much better when it is written in the same order but not all functions are designed in that way. The most important part of this feature is that you can specify only the arguments that you want to be different from the defaults.

The last feature of functions that we are going to discuss is another type of conditional called a guard statement. We have not discussed it until now because it doesn't make much sense unless it is used in a function or loop. A guard statement acts in a similar way to an if statement but the compiler forces you to provide an else condition that must exit from the function, loop, or switch case. Let's rework our addInvitee:ifPossibleToList: function to see what it looks like:

Semantically, the guard statement instructs us to ensure that the number of invitees is less than 20 or else return the original list. This is a reversal of the logic we used before, when we returned the original list if there were 20 or more invitees. This logic actually makes more sense because we are stipulating a prerequisite and providing a failure path. The other nice thing about using the guard statement is that we can't forget to return out of the else condition. If we do, the compiler will give us an error.

It is important to note that guard statements do not have a block of code that is executed if it passes. Only an else condition can be specified with the assumption that any code you want to run for the passing condition will simply come after the statement. This is safe only because the compiler forces the else condition to exit the function and, in turn, ensures that the code after the statement will not run.

Overall, guard statements are a great way of defining preconditions to a function or loop without having to indent your code for the passing case. This is not a big deal for us yet but, if you have lots of preconditions, it often becomes cumbersome to indent the code far enough to handle them.

Parameterized functions

A function

The type of value to be returned from a function is defined after the end of all of the parameters separated by an arrow ->. Let's write a function that takes a list of invitees and one other person to add to the list. If there are spots available, the function adds the person to the list and returns the new version. If there are no spots available, it just returns the original list, as shown here:

In this function, we tested the number of names on the invitee list and, if it was greater than 20, we returned the same list as was passed in to the invitees parameter. Note that return is used in a function in a similar way to break in a loop. As soon as the program executes a line that returns, it exits the function and provides that value to the calling code. So, the final return line is only run if the if statement does not pass. It then adds the newinvitee parameter to the list and returns that to the calling code.

You would call this function like so:

It is important to note that we must assign list to the value returned from our function because it is possible that the new value will be changed by the function. If we did not do this, nothing would happen to the list.

If you try typing this code into a playground, you will notice something very cool. As you begin typing the name of the function, you will see a small pop-up that suggests the name of the function you might want to type, as shown:

Functions that return values

You can use the arrow keys to move up and down the list to select the function you want to type and then press the Tab key to make Xcode finish typing the function for you. Not only that, but it highlights the first parameter so that you can immediately start typing what you want to pass in. When you are done defining the first parameter, you can press Tab again to move on to the next parameter. This greatly increases the speed with which you can write your code.

This is a pretty well-named function because it is clear what it does. However, we can give it a more natural and expressive name by making it read more like a sentence:

This is a great feature of Swift that allows you to have a function called with named parameters. We can do this by giving the second parameter two names, separated by a space. The first name is the one to be used when calling the function, otherwise referred to as the external name. The second name is the one to be used when referring to the constant being passed in from within the function, otherwise referred to as the internal name. As an exercise, try to change the function so that it uses the same external and internal names and see what Xcode suggests. For more of a challenge, write a function that takes a list of invitees and an index for a specific invitee to write a message to ask them to just bring themselves. For example, it would print Sarah, just bring yourself for the index 0 in the preceding list.

Sometimes we write functions where there is a parameter that commonly has the same value. It would be great if we could provide a value for a parameter to be used if the caller did not override that value. Swift has a feature for this called default arguments. To define a default value for an argument, you simply add an equal sign after the argument, followed by the value. We can add a default argument to the sayHelloToName: function, as follows:

This means that we can now call this function with or without specifying a name:

When using default arguments, the order of the arguments becomes unimportant. We can add default arguments to our addInvitee:ifPossibleToList: function and then call it with any combination or order of arguments:

Clearly, the call still reads much better when it is written in the same order but not all functions are designed in that way. The most important part of this feature is that you can specify only the arguments that you want to be different from the defaults.

The last feature of functions that we are going to discuss is another type of conditional called a guard statement. We have not discussed it until now because it doesn't make much sense unless it is used in a function or loop. A guard statement acts in a similar way to an if statement but the compiler forces you to provide an else condition that must exit from the function, loop, or switch case. Let's rework our addInvitee:ifPossibleToList: function to see what it looks like:

Semantically, the guard statement instructs us to ensure that the number of invitees is less than 20 or else return the original list. This is a reversal of the logic we used before, when we returned the original list if there were 20 or more invitees. This logic actually makes more sense because we are stipulating a prerequisite and providing a failure path. The other nice thing about using the guard statement is that we can't forget to return out of the else condition. If we do, the compiler will give us an error.

It is important to note that guard statements do not have a block of code that is executed if it passes. Only an else condition can be specified with the assumption that any code you want to run for the passing condition will simply come after the statement. This is safe only because the compiler forces the else condition to exit the function and, in turn, ensures that the code after the statement will not run.

Overall, guard statements are a great way of defining preconditions to a function or loop without having to indent your code for the passing case. This is not a big deal for us yet but, if you have lots of preconditions, it often becomes cumbersome to indent the code far enough to handle them.

Functions that return values

The type

of value to be returned from a function is defined after the end of all of the parameters separated by an arrow ->. Let's write a function that takes a list of invitees and one other person to add to the list. If there are spots available, the function adds the person to the list and returns the new version. If there are no spots available, it just returns the original list, as shown here:

In this function, we tested the number of names on the invitee list and, if it was greater than 20, we returned the same list as was passed in to the invitees parameter. Note that return is used in a function in a similar way to break in a loop. As soon as the program executes a line that returns, it exits the function and provides that value to the calling code. So, the final return line is only run if the if statement does not pass. It then adds the newinvitee parameter to the list and returns that to the calling code.

You would call this function like so:

It is important to note that we must assign list to the value returned from our function because it is possible that the new value will be changed by the function. If we did not do this, nothing would happen to the list.

If you try typing this code into a playground, you will notice something very cool. As you begin typing the name of the function, you will see a small pop-up that suggests the name of the function you might want to type, as shown:

Functions that return values

You can use the arrow keys to move up and down the list to select the function you want to type and then press the Tab key to make Xcode finish typing the function for you. Not only that, but it highlights the first parameter so that you can immediately start typing what you want to pass in. When you are done defining the first parameter, you can press Tab again to move on to the next parameter. This greatly increases the speed with which you can write your code.

This is a pretty well-named function because it is clear what it does. However, we can give it a more natural and expressive name by making it read more like a sentence:

This is a great feature of Swift that allows you to have a function called with named parameters. We can do this by giving the second parameter two names, separated by a space. The first name is the one to be used when calling the function, otherwise referred to as the external name. The second name is the one to be used when referring to the constant being passed in from within the function, otherwise referred to as the internal name. As an exercise, try to change the function so that it uses the same external and internal names and see what Xcode suggests. For more of a challenge, write a function that takes a list of invitees and an index for a specific invitee to write a message to ask them to just bring themselves. For example, it would print Sarah, just bring yourself for the index 0 in the preceding list.

Sometimes we write functions where there is a parameter that commonly has the same value. It would be great if we could provide a value for a parameter to be used if the caller did not override that value. Swift has a feature for this called default arguments. To define a default value for an argument, you simply add an equal sign after the argument, followed by the value. We can add a default argument to the sayHelloToName: function, as follows:

This means that we can now call this function with or without specifying a name:

When using default arguments, the order of the arguments becomes unimportant. We can add default arguments to our addInvitee:ifPossibleToList: function and then call it with any combination or order of arguments:

Clearly, the call still reads much better when it is written in the same order but not all functions are designed in that way. The most important part of this feature is that you can specify only the arguments that you want to be different from the defaults.

The last feature of functions that we are going to discuss is another type of conditional called a guard statement. We have not discussed it until now because it doesn't make much sense unless it is used in a function or loop. A guard statement acts in a similar way to an if statement but the compiler forces you to provide an else condition that must exit from the function, loop, or switch case. Let's rework our addInvitee:ifPossibleToList: function to see what it looks like:

Semantically, the guard statement instructs us to ensure that the number of invitees is less than 20 or else return the original list. This is a reversal of the logic we used before, when we returned the original list if there were 20 or more invitees. This logic actually makes more sense because we are stipulating a prerequisite and providing a failure path. The other nice thing about using the guard statement is that we can't forget to return out of the else condition. If we do, the compiler will give us an error.

It is important to note that guard statements do not have a block of code that is executed if it passes. Only an else condition can be specified with the assumption that any code you want to run for the passing condition will simply come after the statement. This is safe only because the compiler forces the else condition to exit the function and, in turn, ensures that the code after the statement will not run.

Overall, guard statements are a great way of defining preconditions to a function or loop without having to indent your code for the passing case. This is not a big deal for us yet but, if you have lots of preconditions, it often becomes cumbersome to indent the code far enough to handle them.

Functions with default arguments

Sometimes

The last feature of functions that we are going to discuss is another type of conditional called a guard statement. We have not discussed it until now because it doesn't make much sense unless it is used in a function or loop. A guard statement acts in a similar way to an if statement but the compiler forces you to provide an else condition that must exit from the function, loop, or switch case. Let's rework our addInvitee:ifPossibleToList: function to see what it looks like:

Semantically, the guard statement instructs us to ensure that the number of invitees is less than 20 or else return the original list. This is a reversal of the logic we used before, when we returned the original list if there were 20 or more invitees. This logic actually makes more sense because we are stipulating a prerequisite and providing a failure path. The other nice thing about using the guard statement is that we can't forget to return out of the else condition. If we do, the compiler will give us an error.

It is important to note that guard statements do not have a block of code that is executed if it passes. Only an else condition can be specified with the assumption that any code you want to run for the passing condition will simply come after the statement. This is safe only because the compiler forces the else condition to exit the function and, in turn, ensures that the code after the statement will not run.

Overall, guard statements are a great way of defining preconditions to a function or loop without having to indent your code for the passing case. This is not a big deal for us yet but, if you have lots of preconditions, it often becomes cumbersome to indent the code far enough to handle them.

Guard statement

The last

feature of functions that we are going to discuss is another type of conditional called a guard statement. We have not discussed it until now because it doesn't make much sense unless it is used in a function or loop. A guard statement acts in a similar way to an if statement but the compiler forces you to provide an else condition that must exit from the function, loop, or switch case. Let's rework our addInvitee:ifPossibleToList: function to see what it looks like:

Semantically, the guard statement instructs us to ensure that the number of invitees is less than 20 or else return the original list. This is a reversal of the logic we used before, when we returned the original list if there were 20 or more invitees. This logic actually makes more sense because we are stipulating a prerequisite and providing a failure path. The other nice thing about using the guard statement is that we can't forget to return out of the else condition. If we do, the compiler will give us an error.

It is important to note that guard statements do not have a block of code that is executed if it passes. Only an else condition can be specified with the assumption that any code you want to run for the passing condition will simply come after the statement. This is safe only because the compiler forces the else condition to exit the function and, in turn, ensures that the code after the statement will not run.

Overall, guard statements are a great way of defining preconditions to a function or loop without having to indent your code for the passing case. This is not a big deal for us yet but, if you have lots of preconditions, it often becomes cumbersome to indent the code far enough to handle them.

At this point, we have learned a lot about the basic workings of Swift. Let's take a moment to bring many of these concepts together in a single program. We will also see some new variations on what we have learned.

The goal of the program is to take a list of invitees and a list of television shows and ask random people to bring a show from each genre. It should also ask the rest to just bring themselves.

Before we look at the code, I will mention the three small new features that I will use:

The most important feature is the ability to generate a random number. To do this, we have to import the Foundation framework. This is the most basic framework made available by Apple. As the name suggests, it forms the basis of the framework for both OS X and iOS.

Foundation includes a function called rand that returns a random number. Computers are actually not capable of generating truly random numbers and, by default, rand always returns the same values in the same order. To make it return different values each time the program is run, we use a function called srand that stands for seed random. Seeding random means that we provide a value for rand on which to base its first value. A common way of seeding the random number is using the current time. We will use a method called clock that is also from Foundation.

Lastly, rand returns a number anywhere from 0 to a very large number but, as you will see, we want to restrict the random number to between 0 and the number of invitees. To do this, we use the remainder operator (%). This operator gives you the remainder after dividing the first number by the second number. For example, 14 % 4 returns 2 because 4 goes into 14, 3 times with 2 left over. The great feature of this operator is that it forces a number of any size to always be between 0 and 1 less than the number you are dividing by. This is perfect for changing all of the possible random values.

The full code for generating a random number looks like this:

You may notice one other thing about this code. We are using new syntax UInt32() and Int(). This is a way of changing one type into another. For example, the clock function returns a value of the type clock_t but srand takes a parameter of the type UInt32. Remember, just like with variables, you can hold the option key and click on a function to see what types it takes and returns.

The second feature we will use a variable that can store only true or false. This is called a Bool, which is short for Boolean. We have used this type many times before as it is used in all conditionals and loops but this is the first time that we will store a Bool directly in a variable. At its most basic level, a Boolean variable is defined and used like this:

Note that we can use the Boolean directly in a conditional. This is because a Boolean is the exact type a conditional is expecting. All of our other tests like <= actually result in a Bool.

Lastly, the third feature we will use is a variation of the while loop called a repeat-while loop. The only difference with a repeat-while loop is that the condition is checked at the end of the loop instead of at the beginning. This is significant because, unlike with a while loop, a repeat-while loop will always be executed at least once, as shown:

With this loop, we will continue to generate a random number between 0 and 4 until we get a number that does not equal 3.

Everything else in the code builds off the concepts we already know. I recommend that you read through the code and try to understand it. Try to not only understand it from the perspective of how it works but why I wrote it in that way. I included comments to help explain both what the code is doing and why it is written in that way:

This first section of code gives us a localized place in which to put all of our data. We can easily come back to the program and change the data if we want and we don't have to go searching through the rest of the program to update it:

Here, I have provided a number of functions that simplify more complex code later on in the program. Each one is given a meaningful name so that, when they are used, we do not have to go and look at their code to understand what they are doing:

This last section contains the real logic of the program, which is commonly referred to as the business logic. The functions from the previous section are just details and the final section is the logic that really defines what the program does.

This is far from the only way to organize a program. This will become even clearer as we learn more advanced organization techniques. However, this breakdown shows you the general philosophy behind how you should organize your code. You should strive to write every piece of code as if it were going to be published in a book. Many of the comments in this example will become excessive as you get better with Swift but, when in doubt, explain what you are doing using either a comment or a well-named function. Not only will it help others understand your code, it will also help you understand it when you come back to it in six months and you are a stranger to the code again. Not only that, if you force yourself to formalize your thoughts as you write the code, you will find yourself creating a lot less bugs.

Let's also look at an interesting limitation of this implementation. This program is going to run into a major problem if the number of invitees is less than the number of shows. The repeat-while loop will continue forever, never finding an invitee that was not invited. Your program doesn't have to handle every possible input but you should at least be aware of its limitations.

In this chapter, we have developed a great basis for Swift knowledge. We have learned about the various built-in mechanisms Swift has for representing complex information in expressive and accessible ways. We know that, by default, we should declare information as a constant until we find a practical need to change it, and then we should make it a variable. We have explored how every piece of information in Swift has a type associated with it by the compiler, whether it is through type inference or declared explicitly. We are familiar with many of the built-in types, including simple types like String, Int, and Bool as well as containers like tuples, arrays, and dictionaries. We can use the console output to better investigate our programs, especially by using string interpolation for dynamic output. We recognize the power of controlling the flow of our programs with if statements, conditionals, switches, and loops. We have functions in our skill set to write more legible, maintainable, and reusable code. Finally, we have seen an example of how all of these concepts can be combined to write a full program.

As a challenge to you, I suggest you fix the final program so that it stops trying to assign shows if there are not enough invitees. When you can do that, you are more than ready to move on to the next topic, which is types, scopes, and projects.

These are all tools that we can use to write even more organized code and they will become more critical as we write larger and larger projects.