Home Mobile Swift: Developing iOS Applications

Swift: Developing iOS Applications

By Jon Hoffman , Andrew J Wagner , Giordano Scalzo
books-svg-icon Book
Subscription FREE
eBook + Subscription $29.99
READ FOR FREE Free Trial for 7 days. $15.99 p/m after trial. Cancel Anytime! BUY NOW
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
READ FOR FREE Free Trial for 7 days. $15.99 p/m after trial. Cancel Anytime! BUY NOW
Subscription FREE
eBook + Subscription $29.99
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
  1. Free Chapter
    1. Module 1
About 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.
Publication date:
August 2016
Publisher
Packt
ISBN
9781787120242

   

What are you trying to achieve by reading this book? Learning Swift can be fun, but most of us are trying to achieve something bigger. There is something we want to create, a career we want to follow, or maybe something else entirely. Whatever that goal is, I encourage you to keep it in mind as you read this book. It will be much easier for you to learn, from this or any other resource, if you can always relate it to your goal.

With that in mind, before we dive into learning Swift, we have to understand what it really is and how it will help us in achieving our goals. We also need to move forward with an effective learning technique and get a taste of what is to come. To do all of that, we will cover the following topics in this chapter:

Swift is a programming language developed by Apple primarily to allow developers to continue to push their platforms forward. It is their attempt to make iOS, OS X, watchOS, and tvOS app development more modern, safe, and powerful.

However, Apple has also released Swift as Open Source and begun an effort to add support for Linux with the intent to make Swift even better and a general purpose programming language available everywhere. Some developers have already begun using it to create command-line scripts as a replacement/supplement of the existing scripting languages, such as Python or Ruby and many can't wait to be able to share some of their app code with Web backend code. Apple's priority, at least for now, is to make it the best language possible, to facilitate app development. However, the most important thing to remember is that modern app development almost always requires pulling together multiple platforms into a single-user experience. If a language could bridge those gaps and stay enjoyable to write, safe, and performant, we would have a much easier time making amazing products. Swift is well on its way to reach that goal.

Now, it is important to note that learning Swift is only the first step towards developing. To develop for a device, you must learn the programming language and the frameworks the device maker provides. Being skilled with a programming language is the foundation of getting better at using frameworks and ultimately building apps.

Developing software is like building a table. You can learn the basics of woodworking and nail a few pieces of wood together to make a functional table, but you are very limited in what you can do because you lack advanced woodworking skills. If you want to make a truly great table, you need to step away from the table and focus first on developing your skill set. The better you are at using the tools, the greater the number of possibilities that open up to you to create a more advanced and higher quality piece of furniture. Similarly, with a very limited knowledge of Swift, you can start to piece together a functional app from the code you find online. However, to really make something great, you have to put the time and effort into refining your skill set with the language. Every language feature or technique that you learn opens up more possibilities for your app.

That being said, most developers are driven by a passion to create things and solve problems. We learn best when we can channel our passions into truly improving ourselves and the world around us. We don't want to get stuck learning the minutia of a language with no practical purpose.

The goal of this book is to develop your skills and confidence to dive passionately into creating compelling, maintainable, and elegant apps in Swift. To do that, we will introduce the syntax and features of Swift in a practical way. You will build a rich toolset, while seeing that toolset put to real world usage. So, without further ado, let's jump right into setting up our development environment.

We will start by creating a new Swift playground. As the name suggests, a playground is a place where you can play around with code. With Xcode open, navigate to File | New | Playground… from the menu bar, as shown in the following screenshot:

Running our first swift code

Name it MyFirstPlayground, leave the platform as iOS, and save it wherever you wish.

Once created, a playground window will appear with some code already populated inside it for you:

Running our first swift code

You have already run your first Swift code. A playground in Xcode runs your code every time you make a change and shows you the code results in the sidebar, on the right-hand side of the screen.

Let's break down what this code is doing. The first line is a comment that is ignored while being run. It can be really useful in adding extra information about your code inline with it. In Swift, there are two types of comments: single-line and multi-line. Single-line comments, such as the preceding one, always start with a //. You can also write comments that span multiple lines by surrounding them with /* and */. For example:

As you can see in the preceding screenshot, the second line, import UIKit, imports a framework called UIKit. UIKit is the name of Apple's framework for iOS development. For this example, we are not actually making use of the UIKit framework so it is safe to completely remove that line of code.

Finally, on the last line, the code defines a variable called str that is being assigned to the text "Hello, playground". In the results sidebar, next to that line, you can see that "Hello, playground" was indeed stored in the variable. As your code becomes more complex, this will become incredibly useful to help you track and watch the state of your code, as it is run. Every time you make a change to the code, the results will update, showing you the consequences of the change.

If you are familiar with other programming languages, many of them require some sort of line terminator. In Swift, you do not need anything like that.

The other great thing about Xcode playgrounds is that they will show you errors as you type them in. Let's add a third line to the playground:

On its own, this is completely valid Swift code. It stores the text "Something Else" into a new variable called str. However, when we add this to the playground, we are shown an error in the form of a red exclamation mark next to the line number. If you click on the exclamation mark, you will be shown the full error:

Running our first swift code

This line is highlighted in red and we are shown the Invalid redeclaration of 'str' error. This is because you cannot declare two different variables with the exact same name. Also, notice that the results along the right turned gray instead of black. This indicates that the result being shown is not from the latest code, but the last successful run of the code. The code cannot be successfully run to create a new result because of the error. If we change the second variable to strTwo, the error goes away:

Tip

Downloading the example code

You can download the example code files for this book from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

You can download the code files by following these steps:

  • Log in or register to our website using your e-mail address and password.
  • Hover the mouse pointer on the SUPPORT tab at the top.
  • Click on Code Downloads & Errata.
  • Enter the name of the book in the Search box.
  • Select the book for which you're looking to download the code files.
  • Choose from the drop-down menu where you purchased this book from.
  • Click on Code Download.

Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:

  • WinRAR/7-Zip for Windows
  • Zipeg/iZip/UnRarX for Mac
  • 7-Zip/PeaZip for Linux
Running our first swift code

Now the results are shown in black again, and we can see that they have been updated according to the latest code. Especially if you have experience with other programming environments, the reactiveness of the playground may be surprising to you. Let's take a peek under the hood to get a better understanding of what is happening and how Swift works.

A playground is not truly a program. While it does execute code like a program, it is not really useful outside of the development environment. Before we can understand what the playground is doing for us, we must first understand how Swift works.

Swift is a compiled language, which means that for Swift code to be run, it must first be converted into a form that the computer can actually execute. The tool that does this conversion is called a compiler. A compiler is actually a program and it is also a way to define a programming language.

The Swift compiler takes the Swift code as input and, if it can properly parse and understand the code, outputs machine code. Apple developed the Swift compiler to understand the code according to a series of rules. Those rules are what define the Swift programming language and those rules are what we are trying to learn, when we say we are learning Swift.

Once the machine code is generated, Xcode can wrap the machine code up inside an app that users can run. However, we are running Swift code inside our playground, so clearly building an app is not the only way to run code; something else is going on here.

Every time you make a change to a playground, it automatically tries to compile your code. If it is successful, instead of wrapping up the machine code in an app to be run later, it runs the code immediately and shows you the results. If you had to do this process yourself, you would first have to consciously make the decision to build the code into an app and then run it when you wanted to test something. This would be a huge waste of time; especially, if you write an error that you don't catch until the moment you decide to actually run it. The quicker you can see the result of a code change, the faster you will be at developing the code and the fewer mistakes you will make.

For now, we will be developing all of our code inside a playground because it is a fantastic learning environment. Playgrounds are even more powerful than what we have seen so far and we will see that as we explore deeper into the Swift language.

We are just about ready to get to the meat of learning Swift, but first let's take a moment to make sure that you can get the most out of this book.

 

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.

 

In Chapter 2, Building Blocks – Variables, Collections, and Flow Control, we developed a very simple program that helped organize a party. Even though we separated parts of the code in a logical way, everything was written in a single file and our functions were all lumped together. As projects grow in complexity, this way of organizing code is not sustainable. In the same way we use functions to separate out logical components in our code at scale, we also need to be able to separate out the logical components of our functions and data. To do this, we can define code in different files and we can also create our own types that contain custom data and functionality. These types are commonly referred to as objects, as a part of the programming technique called object-oriented programming. In this chapter we will cover the following:

The most basic way that we can group together data and functionality into a logical unit or object is to define something called a structure. Essentially, a structure is a named collection of data and functions. Actually, we have already seen several different structures because all of the types such as string, array, and dictionary that we have seen so far are structures. Now we will learn how to create our own.

Let's jump straight into defining our first structure to represent a contact:

Here we have created a structure by using the struct keyword followed by a name and curly brackets ({}) with code inside them. Just like with a function, everything about a structure is defined inside its curly brackets. However, code in a structure is not run directly, it is all part of defining what the structure is. Think of a structure as a specification for future behavior instead of code to be run, in the same way that blueprints are the specification for building a house.

Here, we have defined two variables for the first and last name. This code does not create any actual variables nor does it remember any data. As with a function, this code is not truly used until another piece of code uses it. Just like with a string, we have to define a new variable or constant of this type. However, in the past we have always used literals like Sarah or 10. With our own structures, we will have to initialize our own instances, which is just like building a house based on the specifications.

An instance is a specific incarnation of a type. This could be when we create a String variable and assign it the value Sarah. We have created an instance of a String variable that has the value Sarah. The string itself is not a piece of data; it simply defines the nature of instances of String that actually contain data.

Initializing is the formal name for creating a new instance. We initialize a new Contact like this:

You may have noticed that this looks a lot like calling a function and that is because it is very similar. Every type must have at least one special function called an initializer. As the name implies, this is a function that initializes a new instance of the type. All initializers are named after their type and they may or may not have parameters, just like a function. In our case, we have not provided any parameters so the first and last names will be left with the default values that we provided in our specification: First and Last.

You can see this in a playground by clicking on the plus sign next to Contact to the right of that line. This inserts a result pane after the line where it displays the value of firstName and lastName. We have just initialized our first custom type!

If we define a second contact structure that does not provide default values, it changes how we call the initializer. Since there are no default values, we must provide the values when initializing it:

Again, this looks just like calling a function that happens to be named after the type that we defined. Now, someone2 is an instance of Contact2 with firstName equal to Sarah and lastName equal to Smith.

The two variables, firstName and lastName, are called member variables and, if we change them to be constants, they are then called member constants. This is because they are pieces of information associated with a specific instance of the type. You can access member constants and variables on any instance of a structure:

This is in contrast to a static constant. We could add a static constant to our type by adding the following line to its definition:

Note the static keyword before the constant declaration. A static constant is accessed directly from the type and is independent of any instance:

Note that we will be adding code to existing code every so often like this. If you are following along in a playground, you should have added the static let line to the existing Contact structure.

Member and static constants and variables all fall under the category of properties. A property is simply a piece of information associated with an instance or a type. This helps reinforce the idea that every type is an object. A ball, for example, is an object that has many properties including its radius, color, and elasticity. We can represent a ball in code in an object-oriented way by creating a ball structure that has each of those properties:

Note that this Ball type does not define default values for its properties. If default values are not provided in the declaration, they are required when initializing an instance of the type. This means that an empty initializer is not available for that type. If you try to use one, you will get an error:

Just like with normal variables and constants, all properties must have a value once initialized.

Just as you can define constants and variables within a structure, you can also define member and static functions. These functions are referred to as methods to distinguish them from global functions that are not associated with any type. You declare member methods in a similar way to functions but you do so inside the type declaration, as shown:

Member methods always act on a specific instance of the type they are defined in. To access that instance within the method, you use the self keyword. Self acts in a similar way to any other variable in that you can access properties and methods on it. The preceding code prints out the firstName and lastName properties. You call this method in the same way we called methods on any other type:

Within a normal structure method, self is constant, which means you can't modify any of its properties. If you tried, you would get an error like this:

In order for a method to modify self, it must be declared as a mutating method using the mutating keyword:

We can define static properties that apply to the type itself but we can also define static methods that operate on the type by using the static keyword. We can add a static method to our Contact structure that prints the available phone prefixes, as shown here:

In a static method, self refers to the type instead of an instance of the type. In the preceding code, we have used the UnitedStatesPhonePrefix static property through self instead of writing out the type name.

In both static and instance methods, Swift allows you to access properties without using self, for brevity. self is simply implied:

However, if you create a variable in the method with the same name, you will have to use self to distinguish which one you want:

I recommend avoiding this feature of Swift. I want to make you aware of it so you are not confused when looking at other people's code but I feel that always using self greatly increases the readability of your code. self makes it instantly clear that the variable is attached to the instance instead of only defined in the function. You could also create bugs if you add code that creates a variable that hides a member variable. For example, you would create a bug if you introduced the firstName variable to the printFullName method in the preceding code without realizing you were using firstName to access the member variable later in the code. Instead of accessing the member variable, the later code would start to only access the local variable.

You may also have realized that there is another way that we have interacted with a structure in the past. We have used square brackets ([]) with both arrays and dictionaries to access elements. These are called subscripts and we can use them on our custom types as well. The syntax for them is similar to the computed properties that we saw before except that you define it more like a method with parameters and a return type, as you can see here:

You declare the arguments you want to use as the parameters to the subscript method in the square brackets. The return type for the subscript function is the type that will be returned when used to access a value. It is also the type for any value you assign to the subscript:

You may have noticed a question mark (?) in the return type. This is called an optional and we will discuss this more in the next chapter. For now, you only need to know that this is the type that is returned when accessing a dictionary by key because a value does not exist for every possible key.

Just like with computed properties, you can define a subscript as read-only without using the get syntax:

subscript can have as many arguments as you want if you add additional parameters to the subscript declaration. You would then separate each parameter with a comma in the square brackets when using the subscript, as shown:

Subscripts are a good way to shorten your code but you should always be careful to avoid sacrificing clarity for brevity. Writing clear code is a balance between being too wordy and not wordy enough. If your code is too short, it will be hard to understand because meanings will become ambiguous. It is much better to have a method called movieForInvitee: rather than using a subscript. However, if all of your code is too long, there will be too much noise around and you will lose clarity in that way. Use subscripts sparingly and only when they would appear intuitive to another programmer based on the type of structure you are creating.

If you are not satisfied with the default initializers provided to you, you can define your own. This is done using the init keyword, as shown:

Just like with a method, an initializer can take any number of parameters including none at all. However, initializers have other restrictions. One rule is that every member variable and constant must have a value by the end of the initializer. If we were to omit a value for lastName in our initializer, we would get an error like this:

Note that this code did not provide default values for firstName and lastName. If we add that back, we no longer get an error because a value is then provided:

Once you provide your own initializer, Swift no longer provides any default initializers. In the preceding example, Contact can no longer be initialized with the firstName and lastName parameters. If we want both, we have to add our own version of that initializer, as shown:

Another option for setting up the initial values in an initializer is to call a different initializer:

This is a great tool for reducing duplicate code in multiple initializers. However, when using this, there is an extra rule that you must follow. You cannot access self before calling the other initializer:

This is a great example of why the requirement exists. If we were to call print before calling the other initializer, firstName and lastName would not have a value. What would be printed in that case? Instead, you can only access self after calling the other initializer, like this:

This guarantees that all the properties have a valid value before any method is called.

You may have noticed that initializers follow a different pattern for parameter naming. By default, initializers require a label for all parameters. However, remember that this is only the default behavior. You can change the behavior by either providing an internal and external name or by using an underscore (_) as the external name.

Structures are an incredibly powerful tool in programming. They are an important way that we, as programmers, can abstract away more complicated concepts. As we discussed in Chapter 2, Building Blocks – Variables, Collections, and Flow Control, this is the way we get better at using computers. Other people can provide these abstractions to us for concepts that we don't understand yet or in circumstances where it isn't worth our time to start from scratch. We can also use these abstractions for ourselves so that we can better understand the high-level logic going on in our app. This will greatly increase the reliability of our code. Structures make our code more understandable both for other people and for ourselves in the future.

However, structures are limited in one important way, they don't provide a good way to express parent-child relationships between types. For example, a dog and a cat are both animals and share a lot of properties and actions. It would be great if we only had to implement the common attributes once. We could then split those types into different species. For this, Swift has a different system of types called classes.

A class can do everything that a structure can do except that a class can use something called inheritance. A class can inherit the functionality from another class and then extend or customize its behavior. Let's jump right into some code.

Firstly, let's define a class called Building that we can inherit from later:

Predictably, a class is defined using the class keyword instead of struct. Otherwise, a class looks extremely similar to a structure. However, we can also see one difference. With a structure, the initializer we created before would not be necessary because it would have been created for us. With classes, initializers are not automatically created unless all of the properties have default values.

Now let's look at how to inherit from this building class:

Here, we have created a new class called House that inherits from our Building class. This is denoted by the colon (:) followed by Building in the class declaration. Formally, we would say that House is a subclass of Building and Building is a superclass of House.

If we initialize a variable of the type House, we can then access both the properties of House and those of Building, as shown:

This is the beginning of what makes classes powerful. If we need to define ten different types of buildings, we don't have to add a separate squareFootage property to each one. This is true for properties as well as methods.

Beyond a simple superclass and subclass relationship, we can define an entire hierarchy of classes with subclasses of subclasses of subclasses, and so on. It is often helpful to think of a class hierarchy as an upside down tree:

Inheriting from another class

The trunk of the tree is the topmost superclass and each subclass is a separate branch off of that. The topmost superclass is commonly referred to as the base class as it forms the foundation for all the other classes.

Because of the hierarchical nature of classes, the rules for their initializers are more complex. The following additional rules are applied:

The second rule enables us to use self before calling the initializer. However, you cannot use self for any reason other than to initialize its properties.

You may have noticed the use of the keyword super in our house initializer. super is used to reference the current instance as if it were its superclass. This is how we call the superclass initializer. We will see more uses of super when we explore inheritance further later in the chapter.

Inheritance also creates four types of initializers shown here:

A required initializer is a type of initializer for superclasses. If you mark an initializer as required, it forces all of the subclasses to also define that initializer. For example, we could make the Building initializer required, as shown:

Then, if we implemented our own initializer in House, we would get an error like this:

This time, when declaring this initializer, we repeat the required keyword instead of using override:

This is an important tool when your superclass has multiple initializers that do different things. For example, you could have one initializer that creates an instance of your class from a data file and another one that sets its properties from code. Essentially, you have two paths for initialization and you can use the required initializers to make sure that all subclasses take both paths into account. A subclass should still be able to be initialized from both a file and in code. Marking both of the superclass initializers as required makes sure that this is the case.

To discuss designated initializers, we first have to talk about convenience initializers. The normal initializer that we started with is really called a designated initializer. This means that they are core ways to initialize the class. You can also create convenience initializers which, as the name suggests, are there for convenience and are not a core way to initialize the class.

All convenience initializers must call a designated initializer and they do not have the ability to manually initialize properties like a designated initializer does. For example, we can define a convenience initializer on our Building class that takes another building and makes a copy:

Now, as a convenience, you can create a new building using the properties from an existing building. The other rule about convenience initializers is that they cannot be used by a subclass. If you try to do that, you will get an error like this:

This is one of the main reasons that convenience initializers exist. Ideally, every class should only have one designated initializer. The fewer designated initializers you have, the easier it is to maintain your class hierarchy. This is because you will often add additional properties and other things that need to be initialized. Every time you add something like that, you will have to make sure that every designated initializer sets things up properly and consistently. Using a convenience initializer instead of a designated initializer ensures that everything is consistent because it must call a designated initializer that, in turn, is required to set everything up properly. Basically, you want to funnel all of your initialization through as few designated initializers as possible.

Generally, your designated initializer is the one with the most arguments, possibly with all of the possible arguments. In that way, you can call that from all of your other initializers and mark them as convenience initializers.

Just as with initializers, subclasses can override methods and computed properties. However, you have to be more careful with these. The compiler has fewer protections.

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Inheriting from another class

Firstly, let's

define a class called Building that we can inherit from later:

Predictably, a class is defined using the class keyword instead of struct. Otherwise, a class looks extremely similar to a structure. However, we can also see one difference. With a structure, the initializer we created before would not be necessary because it would have been created for us. With classes, initializers are not automatically created unless all of the properties have default values.

Now let's look at how to inherit from this building class:

Here, we have created a new class called House that inherits from our Building class. This is denoted by the colon (:) followed by Building in the class declaration. Formally, we would say that House is a subclass of Building and Building is a superclass of House.

If we initialize a variable of the type House, we can then access both the properties of House and those of Building, as shown:

This is the beginning of what makes classes powerful. If we need to define ten different types of buildings, we don't have to add a separate squareFootage property to each one. This is true for properties as well as methods.

Beyond a simple superclass and subclass relationship, we can define an entire hierarchy of classes with subclasses of subclasses of subclasses, and so on. It is often helpful to think of a class hierarchy as an upside down tree:

Inheriting from another class

The trunk of the tree is the topmost superclass and each subclass is a separate branch off of that. The topmost superclass is commonly referred to as the base class as it forms the foundation for all the other classes.

Because of the hierarchical nature of classes, the rules for their initializers are more complex. The following additional rules are applied:

The second rule enables us to use self before calling the initializer. However, you cannot use self for any reason other than to initialize its properties.

You may have noticed the use of the keyword super in our house initializer. super is used to reference the current instance as if it were its superclass. This is how we call the superclass initializer. We will see more uses of super when we explore inheritance further later in the chapter.

Inheritance also creates four types of initializers shown here:

A required initializer is a type of initializer for superclasses. If you mark an initializer as required, it forces all of the subclasses to also define that initializer. For example, we could make the Building initializer required, as shown:

Then, if we implemented our own initializer in House, we would get an error like this:

This time, when declaring this initializer, we repeat the required keyword instead of using override:

This is an important tool when your superclass has multiple initializers that do different things. For example, you could have one initializer that creates an instance of your class from a data file and another one that sets its properties from code. Essentially, you have two paths for initialization and you can use the required initializers to make sure that all subclasses take both paths into account. A subclass should still be able to be initialized from both a file and in code. Marking both of the superclass initializers as required makes sure that this is the case.

To discuss designated initializers, we first have to talk about convenience initializers. The normal initializer that we started with is really called a designated initializer. This means that they are core ways to initialize the class. You can also create convenience initializers which, as the name suggests, are there for convenience and are not a core way to initialize the class.

All convenience initializers must call a designated initializer and they do not have the ability to manually initialize properties like a designated initializer does. For example, we can define a convenience initializer on our Building class that takes another building and makes a copy:

Now, as a convenience, you can create a new building using the properties from an existing building. The other rule about convenience initializers is that they cannot be used by a subclass. If you try to do that, you will get an error like this:

This is one of the main reasons that convenience initializers exist. Ideally, every class should only have one designated initializer. The fewer designated initializers you have, the easier it is to maintain your class hierarchy. This is because you will often add additional properties and other things that need to be initialized. Every time you add something like that, you will have to make sure that every designated initializer sets things up properly and consistently. Using a convenience initializer instead of a designated initializer ensures that everything is consistent because it must call a designated initializer that, in turn, is required to set everything up properly. Basically, you want to funnel all of your initialization through as few designated initializers as possible.

Generally, your designated initializer is the one with the most arguments, possibly with all of the possible arguments. In that way, you can call that from all of your other initializers and mark them as convenience initializers.

Just as with initializers, subclasses can override methods and computed properties. However, you have to be more careful with these. The compiler has fewer protections.

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Initialization

Because

of the hierarchical nature of classes, the rules for their initializers are more complex. The following additional rules are applied:

The second rule enables us to use self before calling the initializer. However, you cannot use self for any reason other than to initialize its properties.

You may have noticed the use of the keyword super in our house initializer. super is used to reference the current instance as if it were its superclass. This is how we call the superclass initializer. We will see more uses of super when we explore inheritance further later in the chapter.

Inheritance also creates four types of initializers shown here:

A required initializer is a type of initializer for superclasses. If you mark an initializer as required, it forces all of the subclasses to also define that initializer. For example, we could make the Building initializer required, as shown:

Then, if we implemented our own initializer in House, we would get an error like this:

This time, when declaring this initializer, we repeat the required keyword instead of using override:

This is an important tool when your superclass has multiple initializers that do different things. For example, you could have one initializer that creates an instance of your class from a data file and another one that sets its properties from code. Essentially, you have two paths for initialization and you can use the required initializers to make sure that all subclasses take both paths into account. A subclass should still be able to be initialized from both a file and in code. Marking both of the superclass initializers as required makes sure that this is the case.

To discuss designated initializers, we first have to talk about convenience initializers. The normal initializer that we started with is really called a designated initializer. This means that they are core ways to initialize the class. You can also create convenience initializers which, as the name suggests, are there for convenience and are not a core way to initialize the class.

All convenience initializers must call a designated initializer and they do not have the ability to manually initialize properties like a designated initializer does. For example, we can define a convenience initializer on our Building class that takes another building and makes a copy:

Now, as a convenience, you can create a new building using the properties from an existing building. The other rule about convenience initializers is that they cannot be used by a subclass. If you try to do that, you will get an error like this:

This is one of the main reasons that convenience initializers exist. Ideally, every class should only have one designated initializer. The fewer designated initializers you have, the easier it is to maintain your class hierarchy. This is because you will often add additional properties and other things that need to be initialized. Every time you add something like that, you will have to make sure that every designated initializer sets things up properly and consistently. Using a convenience initializer instead of a designated initializer ensures that everything is consistent because it must call a designated initializer that, in turn, is required to set everything up properly. Basically, you want to funnel all of your initialization through as few designated initializers as possible.

Generally, your designated initializer is the one with the most arguments, possibly with all of the possible arguments. In that way, you can call that from all of your other initializers and mark them as convenience initializers.

Just as with initializers, subclasses can override methods and computed properties. However, you have to be more careful with these. The compiler has fewer protections.

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Overriding initializer

An

A required initializer is a type of initializer for superclasses. If you mark an initializer as required, it forces all of the subclasses to also define that initializer. For example, we could make the Building initializer required, as shown:

Then, if we implemented our own initializer in House, we would get an error like this:

This time, when declaring this initializer, we repeat the required keyword instead of using override:

This is an important tool when your superclass has multiple initializers that do different things. For example, you could have one initializer that creates an instance of your class from a data file and another one that sets its properties from code. Essentially, you have two paths for initialization and you can use the required initializers to make sure that all subclasses take both paths into account. A subclass should still be able to be initialized from both a file and in code. Marking both of the superclass initializers as required makes sure that this is the case.

To discuss designated initializers, we first have to talk about convenience initializers. The normal initializer that we started with is really called a designated initializer. This means that they are core ways to initialize the class. You can also create convenience initializers which, as the name suggests, are there for convenience and are not a core way to initialize the class.

All convenience initializers must call a designated initializer and they do not have the ability to manually initialize properties like a designated initializer does. For example, we can define a convenience initializer on our Building class that takes another building and makes a copy:

Now, as a convenience, you can create a new building using the properties from an existing building. The other rule about convenience initializers is that they cannot be used by a subclass. If you try to do that, you will get an error like this:

This is one of the main reasons that convenience initializers exist. Ideally, every class should only have one designated initializer. The fewer designated initializers you have, the easier it is to maintain your class hierarchy. This is because you will often add additional properties and other things that need to be initialized. Every time you add something like that, you will have to make sure that every designated initializer sets things up properly and consistently. Using a convenience initializer instead of a designated initializer ensures that everything is consistent because it must call a designated initializer that, in turn, is required to set everything up properly. Basically, you want to funnel all of your initialization through as few designated initializers as possible.

Generally, your designated initializer is the one with the most arguments, possibly with all of the possible arguments. In that way, you can call that from all of your other initializers and mark them as convenience initializers.

Just as with initializers, subclasses can override methods and computed properties. However, you have to be more careful with these. The compiler has fewer protections.

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Required initializer

A

required initializer is a type of initializer for superclasses. If you mark an initializer as required, it forces all of the subclasses to also define that initializer. For example, we could make the Building initializer required, as shown:

Then, if we implemented our own initializer in House, we would get an error like this:

This time, when declaring this initializer, we repeat the required keyword instead of using override:

This is an important tool when your superclass has multiple initializers that do different things. For example, you could have one initializer that creates an instance of your class from a data file and another one that sets its properties from code. Essentially, you have two paths for initialization and you can use the required initializers to make sure that all subclasses take both paths into account. A subclass should still be able to be initialized from both a file and in code. Marking both of the superclass initializers as required makes sure that this is the case.

To discuss designated initializers, we first have to talk about convenience initializers. The normal initializer that we started with is really called a designated initializer. This means that they are core ways to initialize the class. You can also create convenience initializers which, as the name suggests, are there for convenience and are not a core way to initialize the class.

All convenience initializers must call a designated initializer and they do not have the ability to manually initialize properties like a designated initializer does. For example, we can define a convenience initializer on our Building class that takes another building and makes a copy:

Now, as a convenience, you can create a new building using the properties from an existing building. The other rule about convenience initializers is that they cannot be used by a subclass. If you try to do that, you will get an error like this:

This is one of the main reasons that convenience initializers exist. Ideally, every class should only have one designated initializer. The fewer designated initializers you have, the easier it is to maintain your class hierarchy. This is because you will often add additional properties and other things that need to be initialized. Every time you add something like that, you will have to make sure that every designated initializer sets things up properly and consistently. Using a convenience initializer instead of a designated initializer ensures that everything is consistent because it must call a designated initializer that, in turn, is required to set everything up properly. Basically, you want to funnel all of your initialization through as few designated initializers as possible.

Generally, your designated initializer is the one with the most arguments, possibly with all of the possible arguments. In that way, you can call that from all of your other initializers and mark them as convenience initializers.

Just as with initializers, subclasses can override methods and computed properties. However, you have to be more careful with these. The compiler has fewer protections.

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Designated and convenience initializers

To

discuss designated initializers, we first have to talk about convenience initializers. The normal initializer that we started with is really called a designated initializer. This means that they are core ways to initialize the class. You can also create convenience initializers which, as the name suggests, are there for convenience and are not a core way to initialize the class.

All convenience initializers must call a designated initializer and they do not have the ability to manually initialize properties like a designated initializer does. For example, we can define a convenience initializer on our Building class that takes another building and makes a copy:

Now, as a convenience, you can create a new building using the properties from an existing building. The other rule about convenience initializers is that they cannot be used by a subclass. If you try to do that, you will get an error like this:

This is one of the main reasons that convenience initializers exist. Ideally, every class should only have one designated initializer. The fewer designated initializers you have, the easier it is to maintain your class hierarchy. This is because you will often add additional properties and other things that need to be initialized. Every time you add something like that, you will have to make sure that every designated initializer sets things up properly and consistently. Using a convenience initializer instead of a designated initializer ensures that everything is consistent because it must call a designated initializer that, in turn, is required to set everything up properly. Basically, you want to funnel all of your initialization through as few designated initializers as possible.

Generally, your designated initializer is the one with the most arguments, possibly with all of the possible arguments. In that way, you can call that from all of your other initializers and mark them as convenience initializers.

Just as with initializers, subclasses can override methods and computed properties. However, you have to be more careful with these. The compiler has fewer protections.

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Overriding methods and computed properties

Just as

with initializers, subclasses can override methods and computed properties. However, you have to be more careful with these. The compiler has fewer protections.

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Methods

Even

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Computed properties

It is also

We have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Casting

We

have already talked about how classes are great for sharing functionality between a hierarchy of types. Another thing that makes classes powerful is that they allow code to interact with multiple types in a more general way. Any subclass can be used in code that treats it as if it were its superclass. For example, we might want to write a function that calculates the total square footage of an array of buildings. For this function, we don't care what specific type of building it is, we just need to have access to the squareFootage property that is defined in the superclass. We can define our function to take an array of buildings and the actual array can contain House instances:

Even though this function thinks we are dealing with classes of the type Building, the program will execute the House implementation of squareFootage. If we had also created an office subclass of Building, instances of that would also be included in the array as well with its own implementation.

We can also assign an instance of a subclass to a variable that is defined to be one of its superclasses:

This provides us with an even more powerful abstraction tool than the one we had when using structures. For example, let's consider a hypothetical class hierarchy of images. We might have a base class called Image with subclasses for the different types of encodings like JPGImage and PNGImage. It is great to have the subclasses so that we can cleanly support multiple types of images but, once the image is loaded, we no longer need to be concerned with the type of encoding the image is saved in. Every other class that wants to manipulate or display the image can do so with a well-defined image superclass; the encoding of the image has been abstracted away from the rest of the code. Not only does this create easier to understand code but it also makes maintenance much easier. If we need to add another image encoding like GIF, we can create another subclass and all the existing manipulation and display code can get GIF support with no changes to that code.

There are actually two different types of casting. So far, we have only seen the type of casting called upcasting. Predictably, the other type of casting is called downcasting.

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Upcasting

What

Downcasting means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

Downcasting

Downcasting

means that we treat a superclass as one of its subclasses.

While upcasting can be done implicitly by using it in a function declared to use its superclass or by assigning it to a variable with its superclass type, downcasting must be done explicitly. This is because upcasting cannot fail based on the nature of its inheritance, but downcasting can. You can always treat a subclass as its superclass but you cannot guarantee that a superclass is, in fact, one of its specific subclasses. You can only downcast an instance that is, in fact, an instance of that class or one of its subclasses.

We can force downcast by using the as! Operator, like this:

The as! operator has an exclamation point added to it because it is an operation that can fail. The exclamation point serves as a warning and ensures that you realize that it can fail. If the forced downcasting fails, for example, if someBuilding were not actually House, the program would crash as so:

A safer way to perform downcasting is using the as? operator in a special if statement called an optional binding. We will discuss this in detail in the next chapter, which concerns optionals but, for now, you can just remember the syntax:

This code prints out numberOfBathrooms in the building only if it is of the type House. The House constant is used as a temporary view of someBuilding with its type explicitly set to House. With this temporary view, you can access someBuilding as if it were House instead of just Building.

So far, we have covered two of the three types of classification in Swift: structure and class. The third classification is called enumeration. Enumerations are used to define a group of related values for an instance. For example, if we want values to represent one of the three primary colors, an enumeration is a great tool.

Enumeration instances can be tested for a specific value as with any other type, using the equality operator (==):

Note that, in the second if statement, where color is checked for if it is blue, the code takes advantage of type inference and doesn't bother specifying PrimaryColor.

This method of comparison is familiar and useful for one or two possible values. However, there is a better way to test an enumeration for different values. Instead of using an if statement, you can use a switch. This is a logical solution considering that enumerations are made up of cases and switches test for cases:

This is great for all the same reasons that switches themselves are great. In fact, switches work even better with enumerations because the possible values for an enumeration are always finite, unlike other basic types. You may remember that switches require that you have a case for every possible value. This means that, if you don't have a test case for every case of the enumeration, the compiler will produce an error. This is usually great protection and that is why I recommend using switches rather than simple if statements in most circumstances. If you ever add additional cases to an enumeration, it is great to get an error everywhere in your code that doesn't consider that new case so that you make sure you address it.

Raw values are great for when every case in your enumeration has the same type of value associated with it and its value never changes. However, there are also scenarios where each case has different values associated with it and those values are different for each instance of the enumeration. You may even want a case that has multiple values associated with it. To do this, we use a feature of enumerations called associated values.

You can specify zero or several types to be associated separately with each case with associated values. Then, when creating an instance of the enumeration, you can give it any value you want, as shown:

Here, we have defined an enumeration to store a height measurement using various measurement systems. There is a case for the imperial system that uses feet and inches and a case for the metric system that is in just meters. Both of these cases have labels for their associated values which are similar to a tuple. The last case is there to illustrate that you don't have to provide a label if you don't want to. It simply takes a string.

Comparing and accessing values of enumerations with associated values is a little bit more complex than for regular enumerations. We can no longer use the equality operator (==). Instead, we must always use a case. Within a case, there are multiple ways that you can handle the associated values. The easiest thing to do is to access the specific associated value. To do that, you can assign it to a temporary variable:

In the imperial case, the preceding code assigned feet to a temporary constant and inches to a temporary variable. The names match the labels used for the associated values but that is not necessary. The metric case shows that, if you want all of the temporary values to be constant, you can declare let before the enumeration case. No matter how many associated values there are, let only has to be written once instead of once for every value. The other case is the same as the metric case except that it creates a temporary variable instead of a constant.

If you wanted to create separate cases for conditions on the associated values, you could use the where syntax that we saw in the previous chapter:

Note that we had to add a default case because our restrictions on the other cases were no longer exhaustive.

Lastly, if you don't actually care about the associated value, you can use an underscore (_) to ignore it, as shown:

This shows you that, with enumerations, switches have even more power than we saw previously.

Now that you understand how to use associated values, you might have noticed that they can change the conceptual nature of enumerations. Without associated values, an enumeration represents a list of abstract and constant possible values. An enumeration with associated values is different because two instances with the same case are not necessarily equal; each case could have different associated values. This means that the conceptual nature of enumerations is really a list of ways to look at a certain type of information. This is not a concrete rule but it is common and it gives you a better idea of the different types of information that can best be represented by enumerations. It will also help you make your own enumerations more understandable. Each case could theoretically represent a completely unrelated concept from the rest of the cases using associated values but that should be a sign that an enumeration may not be the best tool for that particular job.

Enumerations are actually very similar to structures. As with structures, enumerations can have methods and properties. To improve the Height enumeration, we could add methods to access the height in any measurement system we wanted. As an example, let's implement a meters method, as follows:

In this method, we have switched on self which tells us which unit of measurement this instance was created with. If it is in meters we can just return that but, if it is in feet and inches, we must do the conversion. As an exercise, I recommend you try to implement a feetAndInches method that returns a tuple with the two values. The biggest challenge is in handling the mathematical operations using the correct types. You cannot perform operations with mismatching types mathematically. If you need to convert from one number type to another, you can do so by initializing a copy as shown in the code above: Double(feet). Unlike the casting that we discussed earlier, this process simply creates a new copy of the feet variable that is now Double instead of Int. This is only possible because the Double type happens to define an initializer that takes Int. Most number types can be initialized with any of the other ones.

You now have a great overview of all of the different ways in which we can organize Swift code in a single file to make the code more understandable and maintainable. It is now time to discuss how we can separate our code into multiple files to improve it even more.

Basic declaration

An

Enumeration instances can be tested for a specific value as with any other type, using the equality operator (==):

Note that, in the second if statement, where color is checked for if it is blue, the code takes advantage of type inference and doesn't bother specifying PrimaryColor.

This method of comparison is familiar and useful for one or two possible values. However, there is a better way to test an enumeration for different values. Instead of using an if statement, you can use a switch. This is a logical solution considering that enumerations are made up of cases and switches test for cases:

This is great for all the same reasons that switches themselves are great. In fact, switches work even better with enumerations because the possible values for an enumeration are always finite, unlike other basic types. You may remember that switches require that you have a case for every possible value. This means that, if you don't have a test case for every case of the enumeration, the compiler will produce an error. This is usually great protection and that is why I recommend using switches rather than simple if statements in most circumstances. If you ever add additional cases to an enumeration, it is great to get an error everywhere in your code that doesn't consider that new case so that you make sure you address it.

Raw values are great for when every case in your enumeration has the same type of value associated with it and its value never changes. However, there are also scenarios where each case has different values associated with it and those values are different for each instance of the enumeration. You may even want a case that has multiple values associated with it. To do this, we use a feature of enumerations called associated values.

You can specify zero or several types to be associated separately with each case with associated values. Then, when creating an instance of the enumeration, you can give it any value you want, as shown:

Here, we have defined an enumeration to store a height measurement using various measurement systems. There is a case for the imperial system that uses feet and inches and a case for the metric system that is in just meters. Both of these cases have labels for their associated values which are similar to a tuple. The last case is there to illustrate that you don't have to provide a label if you don't want to. It simply takes a string.

Comparing and accessing values of enumerations with associated values is a little bit more complex than for regular enumerations. We can no longer use the equality operator (==). Instead, we must always use a case. Within a case, there are multiple ways that you can handle the associated values. The easiest thing to do is to access the specific associated value. To do that, you can assign it to a temporary variable:

In the imperial case, the preceding code assigned feet to a temporary constant and inches to a temporary variable. The names match the labels used for the associated values but that is not necessary. The metric case shows that, if you want all of the temporary values to be constant, you can declare let before the enumeration case. No matter how many associated values there are, let only has to be written once instead of once for every value. The other case is the same as the metric case except that it creates a temporary variable instead of a constant.

If you wanted to create separate cases for conditions on the associated values, you could use the where syntax that we saw in the previous chapter:

Note that we had to add a default case because our restrictions on the other cases were no longer exhaustive.

Lastly, if you don't actually care about the associated value, you can use an underscore (_) to ignore it, as shown:

This shows you that, with enumerations, switches have even more power than we saw previously.

Now that you understand how to use associated values, you might have noticed that they can change the conceptual nature of enumerations. Without associated values, an enumeration represents a list of abstract and constant possible values. An enumeration with associated values is different because two instances with the same case are not necessarily equal; each case could have different associated values. This means that the conceptual nature of enumerations is really a list of ways to look at a certain type of information. This is not a concrete rule but it is common and it gives you a better idea of the different types of information that can best be represented by enumerations. It will also help you make your own enumerations more understandable. Each case could theoretically represent a completely unrelated concept from the rest of the cases using associated values but that should be a sign that an enumeration may not be the best tool for that particular job.

Enumerations are actually very similar to structures. As with structures, enumerations can have methods and properties. To improve the Height enumeration, we could add methods to access the height in any measurement system we wanted. As an example, let's implement a meters method, as follows:

In this method, we have switched on self which tells us which unit of measurement this instance was created with. If it is in meters we can just return that but, if it is in feet and inches, we must do the conversion. As an exercise, I recommend you try to implement a feetAndInches method that returns a tuple with the two values. The biggest challenge is in handling the mathematical operations using the correct types. You cannot perform operations with mismatching types mathematically. If you need to convert from one number type to another, you can do so by initializing a copy as shown in the code above: Double(feet). Unlike the casting that we discussed earlier, this process simply creates a new copy of the feet variable that is now Double instead of Int. This is only possible because the Double type happens to define an initializer that takes Int. Most number types can be initialized with any of the other ones.

You now have a great overview of all of the different ways in which we can organize Swift code in a single file to make the code more understandable and maintainable. It is now time to discuss how we can separate our code into multiple files to improve it even more.

Testing enumeration values

Enumeration

instances can be tested for a specific value as with any other type, using the equality operator (==):

Note that, in the second if statement, where color is checked for if it is blue, the code takes advantage of type inference and doesn't bother specifying PrimaryColor.

This method of comparison is familiar and useful for one or two possible values. However, there is a better way to test an enumeration for different values. Instead of using an if statement, you can use a switch. This is a logical solution considering that enumerations are made up of cases and switches test for cases:

This is great for all the same reasons that switches themselves are great. In fact, switches work even better with enumerations because the possible values for an enumeration are always finite, unlike other basic types. You may remember that switches require that you have a case for every possible value. This means that, if you don't have a test case for every case of the enumeration, the compiler will produce an error. This is usually great protection and that is why I recommend using switches rather than simple if statements in most circumstances. If you ever add additional cases to an enumeration, it is great to get an error everywhere in your code that doesn't consider that new case so that you make sure you address it.

Raw values are great for when every case in your enumeration has the same type of value associated with it and its value never changes. However, there are also scenarios where each case has different values associated with it and those values are different for each instance of the enumeration. You may even want a case that has multiple values associated with it. To do this, we use a feature of enumerations called associated values.

You can specify zero or several types to be associated separately with each case with associated values. Then, when creating an instance of the enumeration, you can give it any value you want, as shown:

Here, we have defined an enumeration to store a height measurement using various measurement systems. There is a case for the imperial system that uses feet and inches and a case for the metric system that is in just meters. Both of these cases have labels for their associated values which are similar to a tuple. The last case is there to illustrate that you don't have to provide a label if you don't want to. It simply takes a string.

Comparing and accessing values of enumerations with associated values is a little bit more complex than for regular enumerations. We can no longer use the equality operator (==). Instead, we must always use a case. Within a case, there are multiple ways that you can handle the associated values. The easiest thing to do is to access the specific associated value. To do that, you can assign it to a temporary variable:

In the imperial case, the preceding code assigned feet to a temporary constant and inches to a temporary variable. The names match the labels used for the associated values but that is not necessary. The metric case shows that, if you want all of the temporary values to be constant, you can declare let before the enumeration case. No matter how many associated values there are, let only has to be written once instead of once for every value. The other case is the same as the metric case except that it creates a temporary variable instead of a constant.

If you wanted to create separate cases for conditions on the associated values, you could use the where syntax that we saw in the previous chapter:

Note that we had to add a default case because our restrictions on the other cases were no longer exhaustive.

Lastly, if you don't actually care about the associated value, you can use an underscore (_) to ignore it, as shown:

This shows you that, with enumerations, switches have even more power than we saw previously.

Now that you understand how to use associated values, you might have noticed that they can change the conceptual nature of enumerations. Without associated values, an enumeration represents a list of abstract and constant possible values. An enumeration with associated values is different because two instances with the same case are not necessarily equal; each case could have different associated values. This means that the conceptual nature of enumerations is really a list of ways to look at a certain type of information. This is not a concrete rule but it is common and it gives you a better idea of the different types of information that can best be represented by enumerations. It will also help you make your own enumerations more understandable. Each case could theoretically represent a completely unrelated concept from the rest of the cases using associated values but that should be a sign that an enumeration may not be the best tool for that particular job.

Enumerations are actually very similar to structures. As with structures, enumerations can have methods and properties. To improve the Height enumeration, we could add methods to access the height in any measurement system we wanted. As an example, let's implement a meters method, as follows:

In this method, we have switched on self which tells us which unit of measurement this instance was created with. If it is in meters we can just return that but, if it is in feet and inches, we must do the conversion. As an exercise, I recommend you try to implement a feetAndInches method that returns a tuple with the two values. The biggest challenge is in handling the mathematical operations using the correct types. You cannot perform operations with mismatching types mathematically. If you need to convert from one number type to another, you can do so by initializing a copy as shown in the code above: Double(feet). Unlike the casting that we discussed earlier, this process simply creates a new copy of the feet variable that is now Double instead of Int. This is only possible because the Double type happens to define an initializer that takes Int. Most number types can be initialized with any of the other ones.

You now have a great overview of all of the different ways in which we can organize Swift code in a single file to make the code more understandable and maintainable. It is now time to discuss how we can separate our code into multiple files to improve it even more.

Raw values

Enumerations

Raw values are great for when every case in your enumeration has the same type of value associated with it and its value never changes. However, there are also scenarios where each case has different values associated with it and those values are different for each instance of the enumeration. You may even want a case that has multiple values associated with it. To do this, we use a feature of enumerations called associated values.

You can specify zero or several types to be associated separately with each case with associated values. Then, when creating an instance of the enumeration, you can give it any value you want, as shown:

Here, we have defined an enumeration to store a height measurement using various measurement systems. There is a case for the imperial system that uses feet and inches and a case for the metric system that is in just meters. Both of these cases have labels for their associated values which are similar to a tuple. The last case is there to illustrate that you don't have to provide a label if you don't want to. It simply takes a string.

Comparing and accessing values of enumerations with associated values is a little bit more complex than for regular enumerations. We can no longer use the equality operator (==). Instead, we must always use a case. Within a case, there are multiple ways that you can handle the associated values. The easiest thing to do is to access the specific associated value. To do that, you can assign it to a temporary variable:

In the imperial case, the preceding code assigned feet to a temporary constant and inches to a temporary variable. The names match the labels used for the associated values but that is not necessary. The metric case shows that, if you want all of the temporary values to be constant, you can declare let before the enumeration case. No matter how many associated values there are, let only has to be written once instead of once for every value. The other case is the same as the metric case except that it creates a temporary variable instead of a constant.

If you wanted to create separate cases for conditions on the associated values, you could use the where syntax that we saw in the previous chapter:

Note that we had to add a default case because our restrictions on the other cases were no longer exhaustive.

Lastly, if you don't actually care about the associated value, you can use an underscore (_) to ignore it, as shown:

This shows you that, with enumerations, switches have even more power than we saw previously.

Now that you understand how to use associated values, you might have noticed that they can change the conceptual nature of enumerations. Without associated values, an enumeration represents a list of abstract and constant possible values. An enumeration with associated values is different because two instances with the same case are not necessarily equal; each case could have different associated values. This means that the conceptual nature of enumerations is really a list of ways to look at a certain type of information. This is not a concrete rule but it is common and it gives you a better idea of the different types of information that can best be represented by enumerations. It will also help you make your own enumerations more understandable. Each case could theoretically represent a completely unrelated concept from the rest of the cases using associated values but that should be a sign that an enumeration may not be the best tool for that particular job.

Enumerations are actually very similar to structures. As with structures, enumerations can have methods and properties. To improve the Height enumeration, we could add methods to access the height in any measurement system we wanted. As an example, let's implement a meters method, as follows:

In this method, we have switched on self which tells us which unit of measurement this instance was created with. If it is in meters we can just return that but, if it is in feet and inches, we must do the conversion. As an exercise, I recommend you try to implement a feetAndInches method that returns a tuple with the two values. The biggest challenge is in handling the mathematical operations using the correct types. You cannot perform operations with mismatching types mathematically. If you need to convert from one number type to another, you can do so by initializing a copy as shown in the code above: Double(feet). Unlike the casting that we discussed earlier, this process simply creates a new copy of the feet variable that is now Double instead of Int. This is only possible because the Double type happens to define an initializer that takes Int. Most number types can be initialized with any of the other ones.

You now have a great overview of all of the different ways in which we can organize Swift code in a single file to make the code more understandable and maintainable. It is now time to discuss how we can separate our code into multiple files to improve it even more.

Associated values

Raw values

are great for when every case in your enumeration has the same type of value associated with it and its value never changes. However, there are also scenarios where each case has different values associated with it and those values are different for each instance of the enumeration. You may even want a case that has multiple values associated with it. To do this, we use a feature of enumerations called associated values.

You can specify zero or several types to be associated separately with each case with associated values. Then, when creating an instance of the enumeration, you can give it any value you want, as shown:

Here, we have defined an enumeration to store a height measurement using various measurement systems. There is a case for the imperial system that uses feet and inches and a case for the metric system that is in just meters. Both of these cases have labels for their associated values which are similar to a tuple. The last case is there to illustrate that you don't have to provide a label if you don't want to. It simply takes a string.

Comparing and accessing values of enumerations with associated values is a little bit more complex than for regular enumerations. We can no longer use the equality operator (==). Instead, we must always use a case. Within a case, there are multiple ways that you can handle the associated values. The easiest thing to do is to access the specific associated value. To do that, you can assign it to a temporary variable:

In the imperial case, the preceding code assigned feet to a temporary constant and inches to a temporary variable. The names match the labels used for the associated values but that is not necessary. The metric case shows that, if you want all of the temporary values to be constant, you can declare let before the enumeration case. No matter how many associated values there are, let only has to be written once instead of once for every value. The other case is the same as the metric case except that it creates a temporary variable instead of a constant.

If you wanted to create separate cases for conditions on the associated values, you could use the where syntax that we saw in the previous chapter:

Note that we had to add a default case because our restrictions on the other cases were no longer exhaustive.

Lastly, if you don't actually care about the associated value, you can use an underscore (_) to ignore it, as shown:

This shows you that, with enumerations, switches have even more power than we saw previously.

Now that you understand how to use associated values, you might have noticed that they can change the conceptual nature of enumerations. Without associated values, an enumeration represents a list of abstract and constant possible values. An enumeration with associated values is different because two instances with the same case are not necessarily equal; each case could have different associated values. This means that the conceptual nature of enumerations is really a list of ways to look at a certain type of information. This is not a concrete rule but it is common and it gives you a better idea of the different types of information that can best be represented by enumerations. It will also help you make your own enumerations more understandable. Each case could theoretically represent a completely unrelated concept from the rest of the cases using associated values but that should be a sign that an enumeration may not be the best tool for that particular job.

Enumerations are actually very similar to structures. As with structures, enumerations can have methods and properties. To improve the Height enumeration, we could add methods to access the height in any measurement system we wanted. As an example, let's implement a meters method, as follows:

In this method, we have switched on self which tells us which unit of measurement this instance was created with. If it is in meters we can just return that but, if it is in feet and inches, we must do the conversion. As an exercise, I recommend you try to implement a feetAndInches method that returns a tuple with the two values. The biggest challenge is in handling the mathematical operations using the correct types. You cannot perform operations with mismatching types mathematically. If you need to convert from one number type to another, you can do so by initializing a copy as shown in the code above: Double(feet). Unlike the casting that we discussed earlier, this process simply creates a new copy of the feet variable that is now Double instead of Int. This is only possible because the Double type happens to define an initializer that takes Int. Most number types can be initialized with any of the other ones.

You now have a great overview of all of the different ways in which we can organize Swift code in a single file to make the code more understandable and maintainable. It is now time to discuss how we can separate our code into multiple files to improve it even more.

Methods and properties

Enumerations

are actually very similar to structures. As with structures, enumerations can have methods and properties. To improve the Height enumeration, we could add methods to access the height in any measurement system we wanted. As an example, let's implement a meters method, as follows:

In this method, we have switched on self which tells us which unit of measurement this instance was created with. If it is in meters we can just return that but, if it is in feet and inches, we must do the conversion. As an exercise, I recommend you try to implement a feetAndInches method that returns a tuple with the two values. The biggest challenge is in handling the mathematical operations using the correct types. You cannot perform operations with mismatching types mathematically. If you need to convert from one number type to another, you can do so by initializing a copy as shown in the code above: Double(feet). Unlike the casting that we discussed earlier, this process simply creates a new copy of the feet variable that is now Double instead of Int. This is only possible because the Double type happens to define an initializer that takes Int. Most number types can be initialized with any of the other ones.

You now have a great overview of all of the different ways in which we can organize Swift code in a single file to make the code more understandable and maintainable. It is now time to discuss how we can separate our code into multiple files to improve it even more.

If we want to move away from developing with a single file, we need to move away from playgrounds and create our first project. In order to simplify the project, we are going to create a command-line tool. This is a program without a graphical interface. As an exercise, we will redevelop our example program from Chapter 2, Building Blocks – Variables, Collections, and Flow Control which managed invitees to a party. We will develop an app with a graphical interface in Chapter 11, A Whole New World – Developing an App.

To create a new command-line tool project, open Xcode and from the menu bar on the top, select File | New | Project…. A window will appear allowing you to select a template for the project. You should choose Command Line Tool from the OS X | Application menu:

Setting up a command-line Xcode project

From there, click Next and then give the project a name like Learning Swift Command Line. Any Organization Name and Identifier are fine. Finally, make sure that Swift is selected from the Language dropdown and click Next again. Now, save the project somewhere that you can find later and click Create.

Xcode will then present you with the project development window. Select the main.swift file on the left and you should see the Hello, World! code that Xcode has generated for you:

Setting up a command-line Xcode project

This should feel pretty similar to a playground except that we can no longer see the output of the code on the right. In a regular project like this, the code is not run automatically for you. The code will still be analyzed for errors as you write it, but you must run it yourself whenever you want to test it. To run the code, you can click the run button on the toolbar, which looks like a play button.

The program will then build and run. Once it does, Xcode shows the console on the bottom where you will see the text Hello, World! which is the result of running this program. This is the same console as we saw in playgrounds.

Unlike a playground, we have the Project Navigator along the left. This is where we organize all of the source files that go into making the application work.

Now that we have successfully created our command-line project, let's create our first new file. It is common to create a separate file for each type that you create. Let's start by creating a file for an invitee class. We want to add the file to the same file group as the main.swift file, so click on that group. You can then click on the plus sign (+) in the lower left of the window and select New File. From that window, select OS X | Source | Swift File and click Next:

Creating and using an external file

The new file will be placed in whatever folder was selected before entering the dialog. You can always drag a file around to organize it however you want. A great place for this file is next to main.swift. Name your new file Invitee.swift and click Create. Let's add a simple Invitee structure to this file. We want Invitee to have a name and to be able to ask them to the party with or without a show:

This is a very simple type and does not require inheritance, so there is no reason to use a class. Note that inheritance is not the only reason to use a class, as we will see in later chapters but, for now, a structure will work great for us. This code provides simple, well-named methods to print out the two types of invites.

We are already making use of a structure that we have not created yet called ShowGenre. We would expect it to have a name and example property. Let's implement that structure now. Create another file called ShowGenre.swift and add the following code to it:

This is an even simpler structure. This is just a small improvement over using a tuple because it is given a name instead of just properties and it also gives us finer control over what is constant or not. It may seem like a waste to have an entire file for just this but this is great for maintainability in the future. It is easier to find the structure because it is in a well-named file and we may want to add more code to it later.

An important principle in code design is called separation of concerns. The idea is that every file and every type should have a clear and well-defined concern. You should avoid having two files or types responsible for the same thing and you want it to be clear why each file and type exists.

Now that we have our basic data structures, we can use a smarter container for our list of invitees. This list contains the logic for assigning a random invitee a genre. Let's start by defining the structure with some properties:

Instead of storing a single list of both invited and pending invitees, we can store them in two separate arrays. This makes selecting a pending invitee much easier. This code also provides a custom initializer, so that all we need to provide from other classes is an invitee list without worrying whether or not it is a list of pending invitees. We could have just used the default initializer but the parameter would then have been named pendingInvitees. We also seed the random number generator for later use.

Note that we did not need to provide a value for invited in our initializer because we gave it the default value of an empty array.

Note also that we are using our Invitee structure freely in this code. Swift automatically finds code from other files in the same project and allows you to use it. Interfacing with code from other files is as simple as that.

Now, let's add a helper function to move an invitee from the pendingInvitee list to the invited list:

This makes our other methods cleaner and easier to understand. The first thing we want to allow is the inviting of a random invitee and then asking them to bring a show from a specific genre:

The picking of a random invitee is much cleaner than in our previous implementation. We can create a random number between 0 and the number of pending invitees instead of having to keep trying a random invitee until we find one that hasn't been invited yet. However, before we can pick that random number, we have to make sure that the number of pending invitees is greater than zero. If there were no remaining invitees we would have to divide the random number by 0 in Int(rand()) % self.pendingInvitees.count. This would cause a crash. It has the extra benefit of allowing us to handle the scenarios where there are more genres than invitees.

Lastly, we want to be able to invite everyone else to just bring themselves:

Here, we have simply repeatedly invited and removed the first pending invitee from the pendingInvitees array until there are none left.

We now have all of our custom types and we can return to the main.swift file to finish the logic of the program. To switch back, you can just click on the file again in Project Navigator (the list of files on the left). Here, all we want to do is to create our invitee list and a list of genres with example shows. Then, we can loop through our genres and ask our invitee list to do the inviting:

That is our complete program. You can now run the program by clicking the Run button and examine the output. You have just completed your first real Swift project!

Setting up a command-line Xcode project

To

create a new command-line tool project, open Xcode and from the menu bar on the top, select File | New | Project…. A window will appear allowing you to select a template for the project. You should choose Command Line Tool from the OS X | Application menu:

Setting up a command-line Xcode project

From there, click Next and then give the project a name like Learning Swift Command Line. Any Organization Name and Identifier are fine. Finally, make sure that Swift is selected from the Language dropdown and click Next again. Now, save the project somewhere that you can find later and click Create.

Xcode will then present you with the project development window. Select the main.swift file on the left and you should see the Hello, World! code that Xcode has generated for you:

Setting up a command-line Xcode project

This should feel pretty similar to a playground except that we can no longer see the output of the code on the right. In a regular project like this, the code is not run automatically for you. The code will still be analyzed for errors as you write it, but you must run it yourself whenever you want to test it. To run the code, you can click the run button on the toolbar, which looks like a play button.

The program will then build and run. Once it does, Xcode shows the console on the bottom where you will see the text Hello, World! which is the result of running this program. This is the same console as we saw in playgrounds.

Unlike a playground, we have the Project Navigator along the left. This is where we organize all of the source files that go into making the application work.

Now that we have successfully created our command-line project, let's create our first new file. It is common to create a separate file for each type that you create. Let's start by creating a file for an invitee class. We want to add the file to the same file group as the main.swift file, so click on that group. You can then click on the plus sign (+) in the lower left of the window and select New File. From that window, select OS X | Source | Swift File and click Next:

Creating and using an external file

The new file will be placed in whatever folder was selected before entering the dialog. You can always drag a file around to organize it however you want. A great place for this file is next to main.swift. Name your new file Invitee.swift and click Create. Let's add a simple Invitee structure to this file. We want Invitee to have a name and to be able to ask them to the party with or without a show:

This is a very simple type and does not require inheritance, so there is no reason to use a class. Note that inheritance is not the only reason to use a class, as we will see in later chapters but, for now, a structure will work great for us. This code provides simple, well-named methods to print out the two types of invites.

We are already making use of a structure that we have not created yet called ShowGenre. We would expect it to have a name and example property. Let's implement that structure now. Create another file called ShowGenre.swift and add the following code to it:

This is an even simpler structure. This is just a small improvement over using a tuple because it is given a name instead of just properties and it also gives us finer control over what is constant or not. It may seem like a waste to have an entire file for just this but this is great for maintainability in the future. It is easier to find the structure because it is in a well-named file and we may want to add more code to it later.

An important principle in code design is called separation of concerns. The idea is that every file and every type should have a clear and well-defined concern. You should avoid having two files or types responsible for the same thing and you want it to be clear why each file and type exists.

Now that we have our basic data structures, we can use a smarter container for our list of invitees. This list contains the logic for assigning a random invitee a genre. Let's start by defining the structure with some properties:

Instead of storing a single list of both invited and pending invitees, we can store them in two separate arrays. This makes selecting a pending invitee much easier. This code also provides a custom initializer, so that all we need to provide from other classes is an invitee list without worrying whether or not it is a list of pending invitees. We could have just used the default initializer but the parameter would then have been named pendingInvitees. We also seed the random number generator for later use.

Note that we did not need to provide a value for invited in our initializer because we gave it the default value of an empty array.

Note also that we are using our Invitee structure freely in this code. Swift automatically finds code from other files in the same project and allows you to use it. Interfacing with code from other files is as simple as that.

Now, let's add a helper function to move an invitee from the pendingInvitee list to the invited list:

This makes our other methods cleaner and easier to understand. The first thing we want to allow is the inviting of a random invitee and then asking them to bring a show from a specific genre:

The picking of a random invitee is much cleaner than in our previous implementation. We can create a random number between 0 and the number of pending invitees instead of having to keep trying a random invitee until we find one that hasn't been invited yet. However, before we can pick that random number, we have to make sure that the number of pending invitees is greater than zero. If there were no remaining invitees we would have to divide the random number by 0 in Int(rand()) % self.pendingInvitees.count. This would cause a crash. It has the extra benefit of allowing us to handle the scenarios where there are more genres than invitees.

Lastly, we want to be able to invite everyone else to just bring themselves:

Here, we have simply repeatedly invited and removed the first pending invitee from the pendingInvitees array until there are none left.

We now have all of our custom types and we can return to the main.swift file to finish the logic of the program. To switch back, you can just click on the file again in Project Navigator (the list of files on the left). Here, all we want to do is to create our invitee list and a list of genres with example shows. Then, we can loop through our genres and ask our invitee list to do the inviting:

That is our complete program. You can now run the program by clicking the Run button and examine the output. You have just completed your first real Swift project!

Creating and using an external file

Now that we have

successfully created our command-line project, let's create our first new file. It is common to create a separate file for each type that you create. Let's start by creating a file for an invitee class. We want to add the file to the same file group as the main.swift file, so click on that group. You can then click on the plus sign (+) in the lower left of the window and select New File. From that window, select OS X | Source | Swift File and click Next:

Creating and using an external file

The new file will be placed in whatever folder was selected before entering the dialog. You can always drag a file around to organize it however you want. A great place for this file is next to main.swift. Name your new file Invitee.swift and click Create. Let's add a simple Invitee structure to this file. We want Invitee to have a name and to be able to ask them to the party with or without a show:

This is a very simple type and does not require inheritance, so there is no reason to use a class. Note that inheritance is not the only reason to use a class, as we will see in later chapters but, for now, a structure will work great for us. This code provides simple, well-named methods to print out the two types of invites.

We are already making use of a structure that we have not created yet called ShowGenre. We would expect it to have a name and example property. Let's implement that structure now. Create another file called ShowGenre.swift and add the following code to it:

This is an even simpler structure. This is just a small improvement over using a tuple because it is given a name instead of just properties and it also gives us finer control over what is constant or not. It may seem like a waste to have an entire file for just this but this is great for maintainability in the future. It is easier to find the structure because it is in a well-named file and we may want to add more code to it later.

An important principle in code design is called separation of concerns. The idea is that every file and every type should have a clear and well-defined concern. You should avoid having two files or types responsible for the same thing and you want it to be clear why each file and type exists.

Now that we have our basic data structures, we can use a smarter container for our list of invitees. This list contains the logic for assigning a random invitee a genre. Let's start by defining the structure with some properties:

Instead of storing a single list of both invited and pending invitees, we can store them in two separate arrays. This makes selecting a pending invitee much easier. This code also provides a custom initializer, so that all we need to provide from other classes is an invitee list without worrying whether or not it is a list of pending invitees. We could have just used the default initializer but the parameter would then have been named pendingInvitees. We also seed the random number generator for later use.

Note that we did not need to provide a value for invited in our initializer because we gave it the default value of an empty array.

Note also that we are using our Invitee structure freely in this code. Swift automatically finds code from other files in the same project and allows you to use it. Interfacing with code from other files is as simple as that.

Now, let's add a helper function to move an invitee from the pendingInvitee list to the invited list:

This makes our other methods cleaner and easier to understand. The first thing we want to allow is the inviting of a random invitee and then asking them to bring a show from a specific genre:

The picking of a random invitee is much cleaner than in our previous implementation. We can create a random number between 0 and the number of pending invitees instead of having to keep trying a random invitee until we find one that hasn't been invited yet. However, before we can pick that random number, we have to make sure that the number of pending invitees is greater than zero. If there were no remaining invitees we would have to divide the random number by 0 in Int(rand()) % self.pendingInvitees.count. This would cause a crash. It has the extra benefit of allowing us to handle the scenarios where there are more genres than invitees.

Lastly, we want to be able to invite everyone else to just bring themselves:

Here, we have simply repeatedly invited and removed the first pending invitee from the pendingInvitees array until there are none left.

We now have all of our custom types and we can return to the main.swift file to finish the logic of the program. To switch back, you can just click on the file again in Project Navigator (the list of files on the left). Here, all we want to do is to create our invitee list and a list of genres with example shows. Then, we can loop through our genres and ask our invitee list to do the inviting:

That is our complete program. You can now run the program by clicking the Run button and examine the output. You have just completed your first real Swift project!

Interfacing with code from other files

Now that

we have our basic data structures, we can use a smarter container for our list of invitees. This list contains the logic for assigning a random invitee a genre. Let's start by defining the structure with some properties:

Instead of storing a single list of both invited and pending invitees, we can store them in two separate arrays. This makes selecting a pending invitee much easier. This code also provides a custom initializer, so that all we need to provide from other classes is an invitee list without worrying whether or not it is a list of pending invitees. We could have just used the default initializer but the parameter would then have been named pendingInvitees. We also seed the random number generator for later use.

Note that we did not need to provide a value for invited in our initializer because we gave it the default value of an empty array.

Note also that we are using our Invitee structure freely in this code. Swift automatically finds code from other files in the same project and allows you to use it. Interfacing with code from other files is as simple as that.

Now, let's add a helper function to move an invitee from the pendingInvitee list to the invited list:

This makes our other methods cleaner and easier to understand. The first thing we want to allow is the inviting of a random invitee and then asking them to bring a show from a specific genre:

The picking of a random invitee is much cleaner than in our previous implementation. We can create a random number between 0 and the number of pending invitees instead of having to keep trying a random invitee until we find one that hasn't been invited yet. However, before we can pick that random number, we have to make sure that the number of pending invitees is greater than zero. If there were no remaining invitees we would have to divide the random number by 0 in Int(rand()) % self.pendingInvitees.count. This would cause a crash. It has the extra benefit of allowing us to handle the scenarios where there are more genres than invitees.

Lastly, we want to be able to invite everyone else to just bring themselves:

Here, we have simply repeatedly invited and removed the first pending invitee from the pendingInvitees array until there are none left.

We now have all of our custom types and we can return to the main.swift file to finish the logic of the program. To switch back, you can just click on the file again in Project Navigator (the list of files on the left). Here, all we want to do is to create our invitee list and a list of genres with example shows. Then, we can loop through our genres and ask our invitee list to do the inviting:

That is our complete program. You can now run the program by clicking the Run button and examine the output. You have just completed your first real Swift project!

File organization and navigation

As your project

Scope is all about which code has access to which other pieces of code. Swift makes it relatively easy to understand because all scope is defined by curly brackets ({}). Essentially, code in curly brackets can only access other code in the same curly brackets.

How scope is defined

To illustrate
Nested types

Sometimes, it is

Swift provides another set of tools that helps to control what code other code has access to called access controls. All code is actually given three levels of access control:

Before we can really discuss this further, you should understand completely what a module is. It is beyond the scope of this book to talk about implementing a module but a module is a collection of code that can be used in other modules and apps. So far, we have used the Foundation module provided by Apple. A module is anything that you use when using the import keyword.

All code, by default, is defined to be at the internal level. That means that any given piece of code in your program can access any piece of code defined in any other file that is also included in your program as long as it follows the scoping rules we have already discussed.

As described previously, code declared as private is only accessible from the same file. This is an even better way to protect outside code from seeing code you don't want it to see. You can declare any variable or type as private by writing the private keyword before it, like this:

Note that access control is independent of the curly bracket scope. It is built on top of it. All of the existing scope rules apply, with access controls acting as an additional filter.

This is a fantastic way of improving the idea of abstractions. The simpler the outside view of your code, the easier it is to understand and use your abstraction. You should look at every file and every type as a small abstraction. In any abstraction, you want the outside world to have as little knowledge of the inner workings of it as possible. You should always keep in mind how you want your abstraction to be used and hide any code that does not serve that purpose. This is because code becomes harder and harder to understand and maintain as the walls between different parts of the code break down. You will end up with code that resembles a bowl of pasta. In the same way that it can be difficult to find where one noodle starts and ends, code with lots of interdependencies and minimal barriers between code components is very hard to make sense of. An abstraction that provides too much knowledge or access about its internal workings is often called a leaky abstraction.

Public code is defined in the same way, except that you would use the public keyword instead of private. However, since we will not study designing your own modules, this is not useful to us. It is good to know it exists for future learning but the default internal access level is enough for our apps.

This was a very dense chapter. We have covered a lot of ground. We have delved deep into defining our own custom types using structures, classes, and enumerations. Structures are great for simple types, while classes are great for types that require a hierarchy of related types. Enumerations provide a way to group related things together and express more abstract concepts through associated values.

We have also created our first project, which made use of multiple source files improving the maintainability of our code bases, especially at scale. Extensions can be used across and within those files to add additional functionality to existing types, including those not defined by us.

Finally, we developed a good understanding of what scope is and how we can control it to our advantage, especially with the help of access controls to give us an even more fine grained filter on what code can interact with other code.

Now that you have made it this far, you are well on your way to becoming a quality Swift programmer. I definitely recommend that you take a breather and experiment with everything that you have learned so far. We have only a few more concepts left to learn until we have all the tools necessary for creating a great app.

Once you are ready to move on, we can talk about optionals, which I have already hinted at. Optionals are somewhat complex but are an integral part of using the Swift language effectively. In the next chapter, we will dive deep into what they are and then how to take advantage of them in the most effective ways possible.

 

As we discussed in Chapter 2, Building Blocks – Variables, Collections, and Flow Control, all variables and constants must always have a value before they are used. This is a great safety feature because it prevents you from creating a scenario where you forget to give a variable an initial value. It may make sense for some number variables, such as the number of sandwiches ordered to start at zero, but it doesn't make sense for all variables. For example, the number of bowling pins standing should start at 10, not zero. In Swift, the compiler forces you to decide what the variable should start at, instead of providing a default value that could be incorrect.

However, there are other scenarios where you will have to represent the complete absence of a value. A great example is if you have a dictionary of word definitions and you try to lookup a word that isn't in the dictionary. Normally, this will return a String, so you could potentially return an empty String, but what if you also need to represent the idea that a word exists without a definition? Also, for another programmer who is using your dictionary, it will not be immediately obvious what will happen when they look up a word that doesn't exist. To satisfy this need to represent the absence of a value, Swift has a special type called an optional.

In this chapter, we will cover the following topics:

So we know that the purpose of optionals in Swift is to allow the representation of the absence of a value, but what does that look like and how does it work? An optional is a special type that can "wrap" any other type. This means that you can make an optional String, optional Array, and so on. You can do this by adding a question mark (?) to the type name, as shown:

Note that this code does not specify any initial values. This is because all optionals, by default, are set to no value at all. If we want to provide an initial value we can do so similar to any other variable:

Also, note that if we left out the type specification (: Int?), possibleInt would be inferred to be of type Int instead of an optional Int.

Now, it is pretty verbose to say that a variable lacks a value. Instead, if an optional lacks a variable, we say it is nil. So both possibleString and possibleArray are nil, while possibleInt is 10. However, possibleInt is not truly 10. It is still wrapped in an optional.

You can see all the forms a variable can take by putting the following code into a playground:

As you can see, actualInt prints out just as we expected, but possibleInt prints out as an optional that contains the value 10 instead of just 10. This is a very important distinction because an optional cannot be used as the value it is wrapping. nilInt just reports that it is nil. At any point, you can update the value within an optional; this includes assigning it a value for the first time, using the assignment operator (=):

You can even remove the value within an optional by assigning it to nil:

So we have this wrapped form of a variable that may or may not contain a value. What do we do if we need to access the value within an optional? The answer is that we must unwrap it.

There are multiple ways to unwrap an optional. All of them essentially assert that there is truly a value within the optional. This is a wonderful safety feature of Swift. The compiler forces you to consider the possibility that an optional lacks any value at all. In other languages, this is a very commonly overlooked scenario that can cause obscure bugs.

The safest way to unwrap an optional is to use something called optional binding. With this technique, you can assign a temporary constant or variable to the value contained within the optional. This process is contained within an if statement, so that you can use an else statement when there is no value. Optional binding looks similar to the following code:

An optional binding is distinguished from an if statement primarily by the if let syntax. Semantically, this code is saying, "if you can let the constant string be equal to the value within possibleString, print out its value; otherwise, print that it has no value." The primary purpose of an optional binding is to create a temporary constant that is the normal (non-optional) version of the optional.

We can also use a temporary variable in an optional binding:

Note that an asterisk (*) is used for multiplication in Swift. You should also notice something important about this code. If you put it into a playground, even though we multiplied the actualInt by 2, the value within the optional does not change. When we print out possibleInt later, the value is still Optional(10). This is because even though we made actualInt a variable (otherwise known as mutable), it is simply a temporary copy of the value within possibleInt. No matter what we do with actualInt, nothing will get changed about the value within possibleInt. If we have to update the actual value stored within possibleInt, we simply assign possibleInt to actualInt after we are done modifying it:

Now, the value wrapped inside possibleInt has actually been updated.

A common scenario that you will probably come across is the need to unwrap multiple optional values. One option is to simply nest the optional bindings:

However, this can be a pain, as it increases the indentation level each time to keep the code organized. Instead, you can actually list multiple optional bindings into a single statement separated by commas:

This generally produces more readable code.

Another great way to do a concise optional binding within functions is to use the guard statement. This way, you can do a series of unwrapping without increasing the indent level of the code at all:

This construct allows us to access the unwrapped values after the guard statement, because the guard statement guarantees that we would have exited the function before reaching that code, if the optional value was nil.

This way of unwrapping is great, but saying that optional binding is the safest way to access the value within an optional, implies that there is an unsafe way to unwrap an optional. This way is called forced unwrapping.

The shortest way to unwrap an optional is to use forced unwrapping. It is done using an exclamation mark (!) after the variable name when being used:

However, the reason it is considered unsafe is that your entire program will crash if you try to unwrap an optional that is currently nil:

The complete error you get is unexpectedly found nil while unwrapping an optional value. This is because the forced unwrapping is essentially your personal guarantee that the optional truly does hold a value. That is why it is called "forced".

Therefore, forced unwrapping should be used in limited circumstances. It should never be used just to shorten up the code. Instead, it should only be used when you can guarantee from the structure of the code that it cannot be nil, even though it is defined as an optional. Even in that case, you should see if it is possible to use a non-optional variable instead. The only other place you may use it is if your program truly could not recover from an optional being nil. In those circumstances, you should at least consider presenting an error to the user, which is always better than simply having your program crash.

An example of a scenario where it may be used effectively is with lazily calculated values. A lazily calculated value is the one that is not created until the first time it is accessed. To illustrate this, let's consider a hypothetical class that represents a file system directory. It will have a property listing its contents that is lazily calculated. The code will look similar to the following code:

Here, we have defined a superclass called FileSystemItem that both File and Directory inherit from. The content of a directory is a list of FileSystemItem. We define contents as a calculated variable and store the real value within the realContents property. The calculated property checks if there is a value loaded for realContents; if there isn't, it loads the contents and puts them into the realContents property. Based on this logic, we know for 100% certainty that there will be a value within realContents by the time we get to the return statement, so it is perfectly safe to use forced unwrapping.

Optional binding

The

safest way to unwrap an optional is to use something called optional binding. With this technique, you can assign a temporary constant or variable to the value contained within the optional. This process is contained within an if statement, so that you can use an else statement when there is no value. Optional binding looks similar to the following code:

An optional binding is distinguished from an if statement primarily by the if let syntax. Semantically, this code is saying, "if you can let the constant string be equal to the value within possibleString, print out its value; otherwise, print that it has no value." The primary purpose of an optional binding is to create a temporary constant that is the normal (non-optional) version of the optional.

We can also use a temporary variable in an optional binding:

Note that an asterisk (*) is used for multiplication in Swift. You should also notice something important about this code. If you put it into a playground, even though we multiplied the actualInt by 2, the value within the optional does not change. When we print out possibleInt later, the value is still Optional(10). This is because even though we made actualInt a variable (otherwise known as mutable), it is simply a temporary copy of the value within possibleInt. No matter what we do with actualInt, nothing will get changed about the value within possibleInt. If we have to update the actual value stored within possibleInt, we simply assign possibleInt to actualInt after we are done modifying it:

Now, the value wrapped inside possibleInt has actually been updated.

A common scenario that you will probably come across is the need to unwrap multiple optional values. One option is to simply nest the optional bindings:

However, this can be a pain, as it increases the indentation level each time to keep the code organized. Instead, you can actually list multiple optional bindings into a single statement separated by commas:

This generally produces more readable code.

Another great way to do a concise optional binding within functions is to use the guard statement. This way, you can do a series of unwrapping without increasing the indent level of the code at all:

This construct allows us to access the unwrapped values after the guard statement, because the guard statement guarantees that we would have exited the function before reaching that code, if the optional value was nil.

This way of unwrapping is great, but saying that optional binding is the safest way to access the value within an optional, implies that there is an unsafe way to unwrap an optional. This way is called forced unwrapping.

The shortest way to unwrap an optional is to use forced unwrapping. It is done using an exclamation mark (!) after the variable name when being used:

However, the reason it is considered unsafe is that your entire program will crash if you try to unwrap an optional that is currently nil:

The complete error you get is unexpectedly found nil while unwrapping an optional value. This is because the forced unwrapping is essentially your personal guarantee that the optional truly does hold a value. That is why it is called "forced".

Therefore, forced unwrapping should be used in limited circumstances. It should never be used just to shorten up the code. Instead, it should only be used when you can guarantee from the structure of the code that it cannot be nil, even though it is defined as an optional. Even in that case, you should see if it is possible to use a non-optional variable instead. The only other place you may use it is if your program truly could not recover from an optional being nil. In those circumstances, you should at least consider presenting an error to the user, which is always better than simply having your program crash.

An example of a scenario where it may be used effectively is with lazily calculated values. A lazily calculated value is the one that is not created until the first time it is accessed. To illustrate this, let's consider a hypothetical class that represents a file system directory. It will have a property listing its contents that is lazily calculated. The code will look similar to the following code:

Here, we have defined a superclass called FileSystemItem that both File and Directory inherit from. The content of a directory is a list of FileSystemItem. We define contents as a calculated variable and store the real value within the realContents property. The calculated property checks if there is a value loaded for realContents; if there isn't, it loads the contents and puts them into the realContents property. Based on this logic, we know for 100% certainty that there will be a value within realContents by the time we get to the return statement, so it is perfectly safe to use forced unwrapping.

Forced unwrapping

The

shortest way to unwrap an optional is to use forced unwrapping. It is done using an exclamation mark (!) after the variable name when being used:

However, the reason it is considered unsafe is that your entire program will crash if you try to unwrap an optional that is currently nil:

The complete error you get is unexpectedly found nil while unwrapping an optional value. This is because the forced unwrapping is essentially your personal guarantee that the optional truly does hold a value. That is why it is called "forced".

Therefore, forced unwrapping should be used in limited circumstances. It should never be used just to shorten up the code. Instead, it should only be used when you can guarantee from the structure of the code that it cannot be nil, even though it is defined as an optional. Even in that case, you should see if it is possible to use a non-optional variable instead. The only other place you may use it is if your program truly could not recover from an optional being nil. In those circumstances, you should at least consider presenting an error to the user, which is always better than simply having your program crash.

An example of a scenario where it may be used effectively is with lazily calculated values. A lazily calculated value is the one that is not created until the first time it is accessed. To illustrate this, let's consider a hypothetical class that represents a file system directory. It will have a property listing its contents that is lazily calculated. The code will look similar to the following code:

Here, we have defined a superclass called FileSystemItem that both File and Directory inherit from. The content of a directory is a list of FileSystemItem. We define contents as a calculated variable and store the real value within the realContents property. The calculated property checks if there is a value loaded for realContents; if there isn't, it loads the contents and puts them into the realContents property. Based on this logic, we know for 100% certainty that there will be a value within realContents by the time we get to the return statement, so it is perfectly safe to use forced unwrapping.

Nil coalescing

In addition

A common scenario in Swift is to have an optional that you must calculate something from. If the optional has a value, you will want to store the result of the calculation on it, but if it is nil, the result should just be set to nil:

This is pretty verbose. To shorten this up in an unsafe way, we could use forced unwrapping:

However, optional chaining will allow us to do this safely. Essentially, it allows optional operations on an optional. When the operation is called, if the optional is nil, it immediately returns nil; otherwise, it returns the result of performing the operation on the value within the optional:

So in this call, invitee is an optional. Instead of unwrapping it, we use optional chaining by placing a question mark (?) after it, followed by the optional operation. In this case, we are asking for the uppercaseInvitee property on it. If invitee is nil, uppercaseInvitee is immediately set to nil without even trying to access uppercaseString. If it actually does contain a value, uppercaseInvitee gets set to the uppercaseString property of the contained value. Note that all optional chains return an optional result.

You can chain as many calls as you want, both optional and non-optional, together in this way:

This code checks if the first element of the invitees-list starts with the letter A, even if it is a lowercase A. First, it uses an optional chain in case invitees is nil. Then the call to first uses an additional optional chain because that method returns an optional String. We then call uppercaseString, which does not return an optional, allowing us to access hasPrefix on the result without having to use another optional chain. If at any point any of the optionals are nil, the result will be nil. This can happen for two different reasons:

If the chain makes it all the way to uppercaseString, there is no longer a failure path and it will definitely return an actual value. You will notice that there are exactly two question marks being used in this chain and there are two possible failure reasons.

At first, it can be hard to understand when you should and should not use a question mark to create a chain of calls; the rule is to always use a question mark if the previous element in the chain returns an optional. However, so you are prepared, let's take a look at what happens if you use an optional chain improperly:

In this case, we try to call a method directly on an optional without a chain, so we get an error that says Value of optional type '[String]?' not unwrapped; did you mean to use '!' or '?'?. Not only does it tell us that the value is not unwrapped, it even suggests two common ways of dealing with the problem: forced unwrapping or optional chaining.

We also have the case where we try to use an optional chain inappropriately:

Here, we get an error that says Cannot use optional chaining on non-optional value of type '[String]'. It is great to have a good sense of the errors you might see when you make mistakes; so that you can correct them quickly because we all make silly mistakes from time-to-time.

Another great feature of optional chaining is that it can be used for method calls on an optional that does not actually return a value:

In this case, we only want to call removeAll if there is truly a value within the optional array. So with this code, if there is a value, all the elements are removed from it; otherwise, it remains nil.

In the end, option chaining is a great choice for writing a concise code that still remains expressive and understandable.

There is a second type of optional called an implicitly unwrapped optional. There are really two ways to look at what an implicitly unwrapped optional is; one way is to say that it is a normal variable that can also be nil; the other way is to say that it is an optional that you don't have to unwrap to use. The important thing to understand about them is that, similar to optionals, they can be nil, but you do not have to unwrap them like a normal variable.

You can define an implicitly unwrapped optional with an exclamation mark (!) instead of a question mark (?) after the type name:

Similar to regular optionals, implicitly unwrapped optionals do not need to be given an initial value because they are nil by default.

At first it may sound like it is the best of both worlds, but in reality it is more like the worst of both worlds. Even though an implicitly unwrapped optional does not have to be unwrapped, it will crash your entire program if it is nil when used:

A great way to think about them is that every time it is used, it is implicitly doing a forced unwrapping. The exclamation mark is placed in its type declaration, instead of each time it is used. This can be problematic because it appears the same as any other variable except for how it is declared. That means it is very unsafe to use, unlike a normal optional.

So if the implicitly unwrapped optionals are the worst of both worlds and are so unsafe, why do they even exist? The reality is that in rare circumstances, they are necessary. They are used in circumstances where a variable is not truly optional, but you also cannot give an initial value to it. This is almost always the case for custom types that have a member variable that is non-optional but cannot be set during initialization.

A rare example of this is with a view in iOS. UIKit, as we discussed before, is the framework Apple provides for iOS development. In it, Apple has a class called UIView that is used to display content on the screen. Apple also provides a tool in Xcode called Interface Builder that lets you design these views in a visual editor instead of in code. Many views designed in this way will need references to other views that can be accessed later, programmatically. When one of these views is loaded, it is initialized without anything connected and then all the connections are made. Once all of the connections are made, a function called awakeFromNib is called on the view. This means that these connections are not available to be used during initialization but are available once awakeFromNib is called. This order of operations also ensures that awakeFromNib is always called before anything actually uses the view. This is a circumstance where it is necessary to use an implicitly unwrapped optional. A member variable may not be able to be defined until after the view is initialized, when it is completely loaded:

Notice that we have actually declared two implicitly unwrapped optionals. The first is a connection to a button. We know that this is a connection because it is preceded by @IBOutlet. This is declared as an implicitly unwrapped optional because connections are not set up until after initialization, but they are still guaranteed to be set up before any other methods are called on the view.

This then leads us to unwrapping our second variable, buttonOriginalWidth, implicitly because we need to wait until the connection is made before we can determine the width of the button. After awakeFromNib is called, it is safe to treat both button and buttonOriginalWidth as non-optional.

You may have noticed that we had to dive pretty deep into app development to find a valid use case for implicitly unwrapped optionals and this is arguably only because UIKit is implemented in Objective-C, as we will learn more about in Chapter 10, Harnessing the Past – Understanding and Translating Objective-C. This is another testament to the fact that they should be used sparingly.

We have already seen a couple of the compiler errors we will commonly see because of optionals. If we try to call a method on an optional that we intended to call on the wrapped value, we will get an error. If we try to unwrap a value that is not actually optional, we will also get an error. We also need to be prepared for the runtime errors that optionals can cause.

As we have discussed, optionals cause runtime errors that are also referred to as crashes, if you try to forcefully unwrap one that is nil. This can happen with both explicit and implicitly forced unwrapping. If you have followed my advice so far in this chapter, this should be a rare occurrence. However, we all end up working with a third party code and maybe they were lazy or maybe they use forced unwrapping to enforce their expectations about how their code should be used.

Also, we all suffer from being lazy from time to time. It can be exhausting or discouraging to worry about all the edge cases when you are excited about programming the core functionality of your app. We may use forced unwrapping temporarily while we worry about that main functionality and plan to come back to handle it later. After all, during development it is better to have a forced unwrapping crash the development version of your app than it is for it to fail silently if you have not yet handled that edge case. We may even decide that an edge case is not worth the development effort of handling because everything about developing an app is a trade off. Either way, we need to recognize a crash from forced unwrapping quickly so we don't waste extra time trying to figure out what went wrong.

When an app tries to unwrap a nil value, if you are currently debugging the app, Xcode will show you the line that is trying to do the unwrapping. The line will report that there was an EXC_BAD_INSTRUCTION error and you will also get a message in the console saying fatal error: unexpectedly found nil while unwrapping an Optional value:

Debugging optionals

You will also sometimes have to look at what code is currently calling the code that failed. To do that, you can use the call stack in Xcode. The call stack is the full path of all function calls that got to this location. So, if you have function1 call function2, which then calls function3, function3 will be at the top and function1 will be at the bottom. Once the execution exits function3, it will be removed from the stack so you will just have function2 on top of function1.

When your program crashes, Xcode will automatically display the call stack, but you can also manually show it by navigating to View | Navigators | Show Debug Navigator. It will look similar to the following screenshot:

Debugging optionals

Here, you can click around different levels of code to see the state of things. This will become even more important if the program is crashing within one of Apple's framework, where you do not have access to the code. In that case, you will want to move up the call stack to the point where your code called into the framework. You may also be able to look at the names of the functions to help you figure out what may have gone wrong.

Anywhere on the call stack, you can look at the state of the variables in the debugger, as shown:

Debugging optionals

If you do not see this variable's view, you can display it by clicking on the button in the bottom-right corner of the screen, second from the right that will be grayed out. Here, you can see that invitee is indeed nil, which is what caused the crash.

As powerful as the debugger is, if you find that it isn't helping you find the problem, you can always put print statements in important parts of the code. It is always safe to print out an optional, as long as you don't forcefully unwrap it as shown in the preceding example. As we have seen before, when an optional is printed, it will print nil if it doesn't have a value, or it will print Optional(<value>) if it has a value.

Debugging is an extremely important part of becoming a productive developer because we all make mistakes and create bugs. Being a great developer means that you can identify problems quickly and understand how to fix them soon after that. This will largely come from practice, but it will also come from having a firm grasp of what is really happening with your code versus simply adapting some code you find online to fit your needs through trial and error.

At this point, you should have a pretty strong grasp of what an optional is and how to use and debug it, but it will be valuable to look a little deeper at optionals to see how they actually work.

In reality, the question mark syntax for optionals is just special shorthand. Writing String? is equivalent to writing Optional<String>. Writing String! is equivalent to writing ImplicitlyUnwrappedOptional<String>. The Swift compiler has the shorthand versions because they are so commonly used. This allows the code to be more concise and readable.

If you declare an optional using the long form, you can see Swift's implementation by holding Command and clicking on the word Optional. Here, you can see that Optional is implemented as an enumeration. Simplifying the code a little, we have:

So we can see that an optional really has two cases: None and Some. None stands for the nil case, while the Some case has an associated value, which is the value wrapped inside the optional. Unwrapping is the process of retrieving the associated value out of the Some case.

The one part of this that you have not seen yet is the angled bracket syntax (<T>). This is called a generic and it essentially allows the enumeration to have an associated value of any type. We will cover generics in-depth in Chapter 6, Make Swift Work For You – Protocols and Generics.

Realizing that optionals are simply enumerations will help you understand how to use them. It also gives you some insight into how concepts are built on top of other concepts. Optionals seem really complex until you realize that they are just a two case enumeration. Once you understand enumerations, you can pretty easily understand optionals as well.

 

So far, we have been programming using the paradigm called object-oriented programming, where everything in a program is represented as an object that can be manipulated and passed around to other objects. This is the most popular way to create apps because it is a very intuitive way to think about software and it goes well with the way Apple has designed their frameworks. However, there are some drawbacks to this technique. The biggest one is that the state of data can be very hard to track and reason about. If we have a thousand different objects floating around in our app, all with different information, it can be hard to track down where the bugs occurred and it can be hard to understand how the whole system fits together. Another paradigm of programming that can help with this problem is called functional programming.

Some programming languages are designed to use only functional programming, but Swift is designed primarily as an object-oriented language with the ability to use functional programming concepts. In this chapter, we will explore how to implement these functional programming concepts in Swift and what they are used for. To do this, we will cover the following topics:

Before we jump into writing code, let's discuss the ideas and motivations behind functional programming.

Functional programming makes it significantly easier to think of each component in isolation. This includes things such as types, functions, and methods. If we can wrap our minds around everything that is input into these code components and everything that should be returned from them, we could analyze the code easily to ensure that there are no bugs and it performs well. Every type is created with a certain number of parameters and each method and function in a program has a certain number of parameters and return values. Normally, we think about these as the only inputs and outputs, but the reality is that often there are more. We refer to these extra inputs and outputs as state.

In a more general sense, state is any stored information, however temporary, that can be changed. Let's consider a simple double function:

This is a great example of a stateless function. No matter what else is happening in the entire universe of the program, this method will always return the same value, if it is given the same input. An input of 2 will always return 4.

Now, let's look at a method with state:

If you call this method repeatedly, with the same input on the same Ball instance, you will get a different result every time. This is because there is an additional input in this method, which is the instance it is being called on. It is otherwise referred to as self. self is actually both an input and an output of this method, because the original value of radius affects the output and radius is changed by the end of the method. This is still not very difficult to reason about, as long as you keep in mind that self is always another input and output. However, you can imagine that with a more complex data structure, it can be hard to track every possible input and output from a piece of code. As soon as that starts to happen, it becomes easier for bugs to get created, because we will almost certainly have, unexpected inputs causing unexpected outputs.

Side effects are an even worse type of extra input or output. They are the unexpected changes to state, seemingly unrelated to the code being run. If we simply rename our preceding method to something a little less clear, its effect on the instance becomes unexpected:

Based on its name, you wouldn't expect this method to change the actual value of radius. This means that if you didn't see the actual implementation, you would expect this method to keep returning the same value if called with the same amount on the same instance. Unpredictability is a terrible thing to have as a programmer.

In its strictest form, functional programming eliminates all state and therefore side effects. We will never go that far in Swift, but we will often use functional programming techniques to reduce state and side effects to increase the predictability of our code, drastically.

Besides predictability, the other effect that functional programming has on our code is that it becomes more declarative. This means that the code shows us how we expect information to flow through our application. This is in contrast to what we have been doing with object-oriented programming, which we call imperative code. This is the difference between writing a code that loops through an array to add only certain elements to a new array and running a filter on the array. The former would look similar to this:

Running a filter on the array would look similar to this:

Don't worry if you don't understand the second example yet. This is what we are going to cover in the rest of this chapter. The general idea is that with imperative codes, we are going to issue a series of commands with the intent of the code as a secondary, subtler idea. To understand that we are creating a copy of originalArray with only elements greater than 3, we have to read the code and mentally step through what is happening. In the second example, we are stating in the code itself that we are filtering the original array. Ultimately, these ideas exist on a spectrum and it is hard to have something be 100% declarative or imperative, but the principles of each are important.

So far, with our imperative code, most of it just defines what our data should look like and how it can be manipulated. Even with high quality abstractions, understanding a section of code can often involve jumping between lots of methods, tracing the execution. In declarative code, logic can be more centralized and often more easily read, based on well-named methods.

You can also think of imperative codes as if it were as a factory where each person makes a car in its entirety while thinking of declarative code as if it were a factory with an assembly line. In order to understand what the person is doing in a non-assembly line factory, you have to watch the whole process unfold one step at a time. They will probably be pulling in all kinds of tools at different times and it will be hard to follow. In a factory with an assembly line, you can determine what is happening by looking at each step in the assembly line one at a time.

Now that we understand some of the motivations of functional programming, let's look at the Swift features that make it possible.

In Swift, functions are considered first-class citizens, which means that they can be treated the same as any other type. They can be assigned to variables and be passed in and out of other functions. When treated this way, we call them closures. This is an extremely critical piece to write more declarative code because it allows us to treat functionalities like objects. Instead of thinking of functions as a collection of code to be executed, we can start to think about them more like a recipe to get something done. Just like you can give just about any recipe to a chef to cook, you can create types and methods that take a closure to perform some customizable behavior.

Let's take a look at how closures work in Swift. The simplest way to capture a closure in a variable is to define the function and then use its name to assign it to a variable:

As you can see, doubleClosure can be used just like the normal function name after being assigned. There is actually no difference between using double and doubleClosure. Note that we can now think of this closure as an object that will double anything passed to it.

If you look at the type of doubleClosure by holding the option key and click on the name, you will see that the type is defined as (Int) -> Int. The basic type of any closure is (ParamterType1, ParameterType2, …) -> ReturnType.

Using this syntax, we can also define our closure inline, such as:

We begin and end any closure with curly brackets ({}). Then, we follow the opening curly bracket with the type for the closure, which will include input parameters and a return value. Finally, we separate the type definition from the actual implementation with the in keyword.

An absence of a return type is defined as Void or (). Even though you may see that some programmers use parentheses, Void is preferred for return declarations:

Essentially, () is an empty tuple meaning it holds no value and it is more commonly used for the input parameters, in case the closure doesn't take any parameters at all:

So far, even though we can change our thinking about the block of code by making it into a closure, it is not terribly useful. To really make closures useful, we need to start passing them into other functions.

We can define a function to take a closure as a parameter, using the same type syntax we saw previously:

Here, we have a function that can find the first number in an array that passes some arbitrary test. The syntax at the end of the function declaration may be confusing but it should be clear if you work from the inside out. The type for passingTest is (number: Int) -> Bool. That is then the second parameter of the whole firstInNumbers function, which returns an Int?. If we want to use this function to find the first number greater than three, we can create a custom test and pass that into the function:

Here, we are essentially passing a little bundle of functionality to the firstInNumbers: function that lets us drastically enhance what a single function can normally do. This is an incredibly useful technique. Looping through an array to find an element can be very verbose. Instead, we can use this function to find an element showing only the important part of the code: the test.

We can even define our test right in a call to the function:

Even though this is more concise, it's pretty complex; hence, Swift allows us to cut out some of the unnecessary syntax.

First, we can make use of type inference for the type of number. The compiler knows that number needs to be Int based on the definition of firstInNumbers:passingTest:. It also knows that the closure has to return Bool. Now, we can rewrite our call, as shown:

This looks cleaner, but the parentheses around number are not required; we could leave those out. In addition, if we have closure as the last parameter of a function, we can provide the closure outside the parentheses for the function call:

Note that the closing parenthesis for the function parameters moved from being after the closure to before it. This is looking pretty great, but we can go even further. For a single line closure, we don't even have to write the return keyword because it is implied:

Lastly, we don't always need to give a name to the parameters of closures. If you leave out the names altogether, each parameter can be referenced using the syntax $<ParemterIndex>. Just like with arrays, the index starts at 0. This helps us write this call very concisely in a single line:

This is a long way from our original syntax. You can mix and match all of these different techniques to make sure that your code is as understandable as possible. As we have discussed before, understandability is a balance between being concise and clear. It is up to you in each circumstance to decide how much syntax you want to cut out. To me, it is not immediately clear what the closure is without it having a name. My preferred syntax for this is to use the parameter name in the call:

This makes it clear that the closure is a test to see which number we want to pull out of the list.

Now that we know what a closure is and how to use one, we can discuss some of the core features of Swift that allow us to write a functional style code.

Closures as variables

Let's take

a look at how closures work in Swift. The simplest way to capture a closure in a variable is to define the function and then use its name to assign it to a variable:

As you can see, doubleClosure can be used just like the normal function name after being assigned. There is actually no difference between using double and doubleClosure. Note that we can now think of this closure as an object that will double anything passed to it.

If you look at the type of doubleClosure by holding the option key and click on the name, you will see that the type is defined as (Int) -> Int. The basic type of any closure is (ParamterType1, ParameterType2, …) -> ReturnType.

Using this syntax, we can also define our closure inline, such as:

We begin and end any closure with curly brackets ({}). Then, we follow the opening curly bracket with the type for the closure, which will include input parameters and a return value. Finally, we separate the type definition from the actual implementation with the in keyword.

An absence of a return type is defined as Void or (). Even though you may see that some programmers use parentheses, Void is preferred for return declarations:

Essentially, () is an empty tuple meaning it holds no value and it is more commonly used for the input parameters, in case the closure doesn't take any parameters at all:

So far, even though we can change our thinking about the block of code by making it into a closure, it is not terribly useful. To really make closures useful, we need to start passing them into other functions.

We can define a function to take a closure as a parameter, using the same type syntax we saw previously:

Here, we have a function that can find the first number in an array that passes some arbitrary test. The syntax at the end of the function declaration may be confusing but it should be clear if you work from the inside out. The type for passingTest is (number: Int) -> Bool. That is then the second parameter of the whole firstInNumbers function, which returns an Int?. If we want to use this function to find the first number greater than three, we can create a custom test and pass that into the function:

Here, we are essentially passing a little bundle of functionality to the firstInNumbers: function that lets us drastically enhance what a single function can normally do. This is an incredibly useful technique. Looping through an array to find an element can be very verbose. Instead, we can use this function to find an element showing only the important part of the code: the test.

We can even define our test right in a call to the function:

Even though this is more concise, it's pretty complex; hence, Swift allows us to cut out some of the unnecessary syntax.

First, we can make use of type inference for the type of number. The compiler knows that number needs to be Int based on the definition of firstInNumbers:passingTest:. It also knows that the closure has to return Bool. Now, we can rewrite our call, as shown:

This looks cleaner, but the parentheses around number are not required; we could leave those out. In addition, if we have closure as the last parameter of a function, we can provide the closure outside the parentheses for the function call:

Note that the closing parenthesis for the function parameters moved from being after the closure to before it. This is looking pretty great, but we can go even further. For a single line closure, we don't even have to write the return keyword because it is implied:

Lastly, we don't always need to give a name to the parameters of closures. If you leave out the names altogether, each parameter can be referenced using the syntax $<ParemterIndex>. Just like with arrays, the index starts at 0. This helps us write this call very concisely in a single line:

This is a long way from our original syntax. You can mix and match all of these different techniques to make sure that your code is as understandable as possible. As we have discussed before, understandability is a balance between being concise and clear. It is up to you in each circumstance to decide how much syntax you want to cut out. To me, it is not immediately clear what the closure is without it having a name. My preferred syntax for this is to use the parameter name in the call:

This makes it clear that the closure is a test to see which number we want to pull out of the list.

Now that we know what a closure is and how to use one, we can discuss some of the core features of Swift that allow us to write a functional style code.

Closures as parameters

We can

define a function to take a closure as a parameter, using the same type syntax we saw previously:

Here, we have a function that can find the first number in an array that passes some arbitrary test. The syntax at the end of the function declaration may be confusing but it should be clear if you work from the inside out. The type for passingTest is (number: Int) -> Bool. That is then the second parameter of the whole firstInNumbers function, which returns an Int?. If we want to use this function to find the first number greater than three, we can create a custom test and pass that into the function:

Here, we are essentially passing a little bundle of functionality to the firstInNumbers: function that lets us drastically enhance what a single function can normally do. This is an incredibly useful technique. Looping through an array to find an element can be very verbose. Instead, we can use this function to find an element showing only the important part of the code: the test.

We can even define our test right in a call to the function:

Even though this is more concise, it's pretty complex; hence, Swift allows us to cut out some of the unnecessary syntax.

First, we can make use of type inference for the type of number. The compiler knows that number needs to be Int based on the definition of firstInNumbers:passingTest:. It also knows that the closure has to return Bool. Now, we can rewrite our call, as shown:

This looks cleaner, but the parentheses around number are not required; we could leave those out. In addition, if we have closure as the last parameter of a function, we can provide the closure outside the parentheses for the function call:

Note that the closing parenthesis for the function parameters moved from being after the closure to before it. This is looking pretty great, but we can go even further. For a single line closure, we don't even have to write the return keyword because it is implied:

Lastly, we don't always need to give a name to the parameters of closures. If you leave out the names altogether, each parameter can be referenced using the syntax $<ParemterIndex>. Just like with arrays, the index starts at 0. This helps us write this call very concisely in a single line:

This is a long way from our original syntax. You can mix and match all of these different techniques to make sure that your code is as understandable as possible. As we have discussed before, understandability is a balance between being concise and clear. It is up to you in each circumstance to decide how much syntax you want to cut out. To me, it is not immediately clear what the closure is without it having a name. My preferred syntax for this is to use the parameter name in the call:

This makes it clear that the closure is a test to see which number we want to pull out of the list.

Now that we know what a closure is and how to use one, we can discuss some of the core features of Swift that allow us to write a functional style code.

Syntactic sugar

First, we

can make use of type inference for the type of number. The compiler knows that number needs to be Int based on the definition of firstInNumbers:passingTest:. It also knows that the closure has to return Bool. Now, we can rewrite our call, as shown:

This looks cleaner, but the parentheses around number are not required; we could leave those out. In addition, if we have closure as the last parameter of a function, we can provide the closure outside the parentheses for the function call:

Note that the closing parenthesis for the function parameters moved from being after the closure to before it. This is looking pretty great, but we can go even further. For a single line closure, we don't even have to write the return keyword because it is implied:

Lastly, we don't always need to give a name to the parameters of closures. If you leave out the names altogether, each parameter can be referenced using the syntax $<ParemterIndex>. Just like with arrays, the index starts at 0. This helps us write this call very concisely in a single line:

This is a long way from our original syntax. You can mix and match all of these different techniques to make sure that your code is as understandable as possible. As we have discussed before, understandability is a balance between being concise and clear. It is up to you in each circumstance to decide how much syntax you want to cut out. To me, it is not immediately clear what the closure is without it having a name. My preferred syntax for this is to use the parameter name in the call:

This makes it clear that the closure is a test to see which number we want to pull out of the list.

Now that we know what a closure is and how to use one, we can discuss some of the core features of Swift that allow us to write a functional style code.

The first thing to realize is that Swift is not a functional programming language. At its core, it will always be an object-oriented programming language. However, since functions in Swift are first-class citizens, we can use some of the core techniques. Swift provides some built-in methods to get us started.

Swift also provides a method called reduce. The purpose of reduce is to condense a list down to a single value. Reduce works by iterating over every value and combining it with a single value that represents all previous elements. This is just like mixing a bunch of ingredients in a bowl for a recipe. We will take one ingredient at a time and combine it in the bowl until we are left with just a single bowl of ingredients.

Let's take a look at what the reduce function looks like in our code. We can use it to sum up the values in our number array:

As you can see, reduce takes two parameters. The first parameter is a value with which to start combining each item in the list. The second is a closure that will do the combining. Similar to filter, this closure is called once for each element in the array. The first parameter of the closure is the value after combing each of the previous elements with the initial value. The second parameter is the next element.

So the first time the closure is called, it is called with 0 (the initial value) and 1 (the first element of the list); it then returns 1. This means that it is then called again with 1 (the value from the last call) and 2 (the next element in the list) returning 3. This will continue until it is combining the running sum of 10, with the last element 5, returning a final result of 15. It becomes very simple once we break it down.

Reduce is another great vocabulary item to add to our skill-set. It can reduce any list of information into a single value by analyzing data to generate a document from a list of images and much more.

Also, we can start to chain our functions together. If we want to find the sum of all the even numbers in our list, we can run the following code:

Now, we can actually do one more thing to shorten this. Every arithmetic operation, including addition (+) is really just another function or closure. Addition is a function that takes two values of the same type and returns their sum. This means that we can simply pass the addition function as our combine closure:

Now we are getting fancy!

Also, keep in mind that the combined value does not need to be the same type that is in the original list. Instead of summing the values, we could combine them all into one string:

Here I am using string interpolation to create a string that starts with the running value and ends with the next element.

Filter

The first

Swift also provides a method called reduce. The purpose of reduce is to condense a list down to a single value. Reduce works by iterating over every value and combining it with a single value that represents all previous elements. This is just like mixing a bunch of ingredients in a bowl for a recipe. We will take one ingredient at a time and combine it in the bowl until we are left with just a single bowl of ingredients.

Let's take a look at what the reduce function looks like in our code. We can use it to sum up the values in our number array:

As you can see, reduce takes two parameters. The first parameter is a value with which to start combining each item in the list. The second is a closure that will do the combining. Similar to filter, this closure is called once for each element in the array. The first parameter of the closure is the value after combing each of the previous elements with the initial value. The second parameter is the next element.

So the first time the closure is called, it is called with 0 (the initial value) and 1 (the first element of the list); it then returns 1. This means that it is then called again with 1 (the value from the last call) and 2 (the next element in the list) returning 3. This will continue until it is combining the running sum of 10, with the last element 5, returning a final result of 15. It becomes very simple once we break it down.

Reduce is another great vocabulary item to add to our skill-set. It can reduce any list of information into a single value by analyzing data to generate a document from a list of images and much more.

Also, we can start to chain our functions together. If we want to find the sum of all the even numbers in our list, we can run the following code:

Now, we can actually do one more thing to shorten this. Every arithmetic operation, including addition (+) is really just another function or closure. Addition is a function that takes two values of the same type and returns their sum. This means that we can simply pass the addition function as our combine closure:

Now we are getting fancy!

Also, keep in mind that the combined value does not need to be the same type that is in the original list. Instead of summing the values, we could combine them all into one string:

Here I am using string interpolation to create a string that starts with the running value and ends with the next element.

Reduce

Swift also

provides a method called reduce. The purpose of reduce is to condense a list down to a single value. Reduce works by iterating over every value and combining it with a single value that represents all previous elements. This is just like mixing a bunch of ingredients in a bowl for a recipe. We will take one ingredient at a time and combine it in the bowl until we are left with just a single bowl of ingredients.

Let's take a look at what the reduce function looks like in our code. We can use it to sum up the values in our number array:

As you can see, reduce takes two parameters. The first parameter is a value with which to start combining each item in the list. The second is a closure that will do the combining. Similar to filter, this closure is called once for each element in the array. The first parameter of the closure is the value after combing each of the previous elements with the initial value. The second parameter is the next element.

So the first time the closure is called, it is called with 0 (the initial value) and 1 (the first element of the list); it then returns 1. This means that it is then called again with 1 (the value from the last call) and 2 (the next element in the list) returning 3. This will continue until it is combining the running sum of 10, with the last element 5, returning a final result of 15. It becomes very simple once we break it down.

Reduce is another great vocabulary item to add to our skill-set. It can reduce any list of information into a single value by analyzing data to generate a document from a list of images and much more.

Also, we can start to chain our functions together. If we want to find the sum of all the even numbers in our list, we can run the following code:

Now, we can actually do one more thing to shorten this. Every arithmetic operation, including addition (+) is really just another function or closure. Addition is a function that takes two values of the same type and returns their sum. This means that we can simply pass the addition function as our combine closure:

Now we are getting fancy!

Also, keep in mind that the combined value does not need to be the same type that is in the original list. Instead of summing the values, we could combine them all into one string:

Here I am using string interpolation to create a string that starts with the running value and ends with the next element.

Map

Map is a
Sort

The last built-in
How these affect the state and nature of code

There are more

A powerful feature of Swift is the ability to make these operations lazily evaluated. This means that, just like a lazy person would do, a value is only calculated when it is absolutely necessary and at the latest point possible.

First, it is important to realize the order in which these methods are executed. For example, what if we only want the first element of our numbers to be mapped to strings:

This works well, except that we actually converted every number to a string to get to just the first one. That is because each step of the chain is completed in its entirety before the next one can be executed. To prevent this, Swift has a built-in method called lazy.

Lazy creates a new version of a container that only pulls specific values from it when it is specifically requested. This means that lazy essentially allows each element to flow through a series of functions one at a time, as it is needed. You can think about it like a lazy version of a worker. If you ask someone lazy to look up the capital of Cameroon, they aren't going to compile a list of the capitals of all countries before they get the answer. They are only going to do the work necessary to get that specific answer. That work may involve multiple steps, but they would only have to do those steps for the specific countries you ask for.

Now, let's look at what lazy looks like in code. You use it to convert a normal list into a lazy list:

Now, instead of calling map directly on numbers, we called it on the lazy version of numbers. This makes it so that every time a value is requested from the result, it only processes a single element out of the input array. In our preceding example, the map method will only have been performed once.

This even applies to looping through a result:

Each number is converted to a string only upon the next iteration of the for-in loop. If we were to break out of that loop early, the rest of the values would not be calculated. This is a great way to save processing time, especially on large lists.

Let's take a look at what this looks like in practice. We can use some of the techniques we learned in this chapter to write a different and possibly better implementation of our party inviter.

We can start by defining the same input data:

In this implementation, we are making the invitees list, which is just a constant list of names and the shows by genre dictionary variable. This is because we are going to be mapping our invitees list to a list of invitation text. As we do the mapping, we will have to pick a random genre to assign to the current invitee, and in order to avoid assigning the same genre more than once, we can remove the genre from the dictionary.

So let's write the random genre function:

We start by creating an array of just the keys of the shows by genre dictionary. Then, if there are no genres left, we simply return nil. Otherwise, we pick out a random genre, remove it from the dictionary, and return it and the show example.

Now we can use that function to map the invitees to a list of invitations:

Here we try to pick a random genre. If we can't, we return an invitation saying that the invitee should just bring themselves. If we can, we return an invitation saying what genre they should bring with the example show. The one new thing to note here is that we are using the sequence "\n" in our string. This is a newline character and it signals that a new line should be started in the text.

The last step is to print out the invitations. To do that, we can print out the invitations as a string joined by newline characters:

This works pretty well but there is one problem. The first invitees we listed will always be assigned a genre because the order they are processed in never changes. To fix this, we can write a function to shuffle the invitees before we begin to map the function:

In order to shuffle an array, we go through three steps: First, we map the array to a tuple with the original element and a random number. Second, we sort the tuples based on those random numbers. Finally, we map the tuples back to just their original elements.

Now, all we have to do is add a call to this function to our sequence:

This implementation is not necessarily better than our previous implementations, but it definitely has its advantages. We have taken steps towards reducing the state by implementing it as a series of data transformations. The big hiccup in that is that we are still maintaining state in the genre dictionary. We can certainly do more to eliminate that as well, but this gives you a good idea of how we can start to think about problems in a functional way. The more ways in which we can think about a problem, the higher our odds of coming up with the best solution.

 

As we learned in Chapter 2, Building Blocks – Variables, Collections, and Flow Control, Swift is a strongly typed language, which means that every piece of data must have a type. Not only can we take advantage of this to reduce the clutter in our code, we can also leverage it to let the compiler catch bugs for us. The earlier we catch a bug, the better. Besides not writing them in the first place, the earliest place where we can catch a bug is when the compiler reports an error.

Two big tools that Swift provides to achieve this are called protocols and generics. Both of them use the type system to make our intentions clear to the compiler so that it can catch more bugs for us.

In this chapter, we will cover the following topics:

The first tool we will look at is protocols. A protocol is essentially a contract that a type can sign, specifying that it will provide a certain interface to other components. This relationship is significantly looser than the relationship a subclass has with its superclass. A protocol does not provide any implementation to the types that implement them. Instead, a type can implement them in any way that they like.

Let's take a look at how we define a protocol, in order to understand them better.

Let's say we have some code that needs to interact with a collection of strings. We don't actually care what order they are stored in and we only need to be able to add and enumerate elements inside the container. One option would be to simply use an array, but an array does way more than we need it to. What if we decide later that we would rather write and read the elements from the file system? Furthermore, what if we want to write a container that would intelligently start using the file system as it got really large? We can make our code flexible enough to do this in the future by defining a string container protocol, which is a loose contract that defines what we need it to do. This protocol might look similar to the following code:

Predictably, a protocol is defined using the protocol keyword, similar to a class or a structure. It also allows you to specify computed properties and methods. You cannot declare a stored property because it is not possible to create an instance of a protocol directly. You can only create instances of types that implement the protocol. Also, you may notice that none of the computed properties or methods provide implementations. In a protocol, you only provide the interface.

Since protocols cannot be initialized on their own, they are useless until we create a type that implements them. Let's take a look at how we can create a type that implements our StringContainer protocol.

A type "signs the contract" of a protocol in the same way that a class inherits from another class except that structures and enumerations can also implement protocols:

As you can see, once a type has claimed to implement a specific protocol, the compiler will give an error if it has not fulfilled the contract by implementing everything defined in the protocol. To satisfy the compiler, we must now implement the count computed property, mutating function addString:, and function enumerateStrings: as they are defined. We will do this by internally holding our values in an array:

The count property will always just return the number of elements in our strings array. The addString: method can simply add the string to our array. Finally, our enumerateString: method just needs to loop through our array and call the handler with each element.

At this point, the compiler is satisfied that StringBag is fulfilling its contract with the StringContainer protocol.

Now, we can similarly create a class that implements the StringContainer protocol. This time, we will implement it using an internal dictionary instead of an array:

Here we can see that a class can both inherit from a superclass and implement a protocol. The superclass always has to come first in the list, but you can implement as many protocols as you want, separating each one with a comma. In fact, a structure and enumeration can also implement multiple protocols.

With this implementation we are doing something slightly strange with the dictionary. We defined it to have no values; it is simply a collection of keys. This allows us to store our strings without any regard to the order they are in.

Now, when we create instances, we can actually assign any instance of any type that implements our protocol to a variable that is defined to be our protocol, just like we can with superclasses:

When a variable is defined with our protocol as its type, we can only interact with it using the interface that the protocol defines. This is a great way to abstract implementation details and create more flexible code. By being less restrictive on the type that we want to use, we can easily change our code without affecting how we use it. Protocols provide the same benefit that superclasses do, but in an even more flexible and comprehensive way, because they can be implemented by all types and a type can implement an unlimited number of protocols. The only benefit that superclasses provide over protocols is that superclasses share their implementations with their children.

Protocols can be made more flexible using a feature called type aliases. They act as a placeholder for a type that will be defined later when the protocol is being implemented. For example, instead of creating an interface that specifically includes strings, we can create an interface for a container that can hold any type of value, as shown:

As you can see, this protocol creates a type alias called Element using the keyword typealias. It does not actually specify a real type; it is just a placeholder for a type that will be defined later. Everywhere we have previously used a string, we simply refer to it as Element.

Now, we can create another string bag that uses the new Container protocol with a type alias instead of the StringContainer protocol. To do this, we not only need to implement each of the methods, we also need to give a definition for the type alias, as shown:

With this code, we have specified that the Element type alias should be a string for this implementation using an equal sign (=). This code continues to use the type alias for all of the properties and methods, but you can also use string since they are in fact the same thing now.

Using the type alias actually makes it really easy for us to create another structure that can hold integers instead of strings:

The only difference between these two pieces of code is that the type alias has been defined to be an integer in the second case instead of a string. We could use copy and paste to create a container of virtually any type, but as usual, doing a lot of copy and paste is a sign that there is a better solution. Also, you may notice that our new Container protocol isn't actually that useful on its own because with our existing techniques, we can't treat a variable as just a Container. If we are going to interact with an instance that implements this protocol, we need to know what type it has assigned the type alias to.

Swift provides a tool called generics to solve both of these problems.

A generic is very similar to a type alias. The difference is that the exact type of a generic is determined by the context in which it is being used, instead of being determined by the implementing types. This also means that a generic only has a single implementation that must support all possible types. Let's start by defining a generic function.

In Chapter 5, A Modern Paradigm – Closures and Functional Programming, we created a function that helped us find the first number in an array of numbers that passes a test:

This would be great if we only ever dealt with arrays of integers, but clearly it would be helpful to be able to do this with other types. In fact, dare I say, all types? We achieve this very simply by making our function generic. A generic function is declared similar to a normal function, but you include a list of comma-separated placeholders inside angled brackets (<>) at the end of the function name, as shown:

In this function, we have declared a single placeholder called ValueType. Just like with type aliases, we can continue to use this type in our implementation. This will stand in for a single type that will be determined when we go to use the function. You can imagine inserting String or any other type into this code instead of ValueType and it would still work.

We use this function similarly to any other function, as shown:

Here, we have used firstInArray:passingTest: with both an array of strings and an array of numbers. The compiler figures out what type to substitute in for the placeholder based on the variables we pass into the function. In the first case, strings is an array of String. It compares that to [ValueType] and assumes that we want to replace ValueType with String. The same thing happens with our Int array in the second case.

So what happens if the type we use in our closure doesn't match the type of array we pass in?

As you can see, we get an error that the types don't match.

You may have noticed that we have actually used generic functions before. All of the built in functions we looked at in Chapter 5, A Modern Paradigm – Closures and Functional Programming, such as map and filter are generic; they can be used with any type.

We have even experienced generic types before. Arrays and dictionaries are also generic. The Swift team didn't have to write a new implementation of array and dictionary for every type that we might want to use inside the containers; they created them as generic types.

Similar to a generic function, a generic type is defined just like a normal type but it has a list of placeholders at the end of its name. Earlier in this chapter, we created our own containers for strings and integers. Let's make a generic version of these containers, as shown:

This implementation looks similar to our type alias versions, but we are using the ElementType placeholder instead.

While a generic function's placeholders are determined when the function is called, a generic type's placeholders are determined when initializing new instances:

All future interactions with a generic instance must use the same types for its placeholders. This is actually one of the beauties of generics where the compiler does work for us. If we create an instance of one type and accidently try to use it as a different type, the compiler won't let us. This protection does not exist in many other programming languages, including Apple's previous language: Objective-C.

One interesting case to consider is if we try to initialize a bag with an empty array:

As you can see, we get an error that the compiler could not determine the type to assign to our generic placeholder. We can solve this by giving an explicit type to the generic we are assigning it to:

This is great because not only can the compiler determine the generic placeholder types based on the variables we pass to them, it can also determine the type based on how we are using the result.

We have already seen how to use generics in a powerful way. We solved the first problem we discussed in the type alias section about copying and pasting a bunch of implementations for different types. However, we have not yet figured out how to solve the second problem: how do we write a generic function to handle any type of our Container protocol? The answer is that we can use type constraints.

Before we jump right into solving the problem, let's take a look at a simpler form of type constraints.

Let's say that we want to write a function that can determine the index of an instance within an array using an equality check. Our first attempt will probably look similar to the following code:

With this attempt, we get an error that we cannot invoke the equality operator (==). This is because our implementation must work for any possible type that might be assigned to our placeholder. Not every type in Swift can be tested for equality. To fix this problem, we can use a type constraint to tell the compiler that we only want to allow our function to be called with types that support the equality operation. We add type constraints by requiring the placeholder to implement a protocol. In this case, Swift provides a protocol called Equatable, which we can use:

A type constraint looks similar to a type implementing a protocol using a colon (:) after a placeholder name. Now, the compiler is satisfied that every possible type can be compared using the equality operator. If we were to try to call this function with a type that is not equatable, the compiler would produce an error:

This is another case where the compiler can save us from ourselves.

We can also add type constraints to our generic types. For example, if we tried to create a bag with our dictionary implementation without a constraint, we would get an error:

This is because the key of dictionaries has a constraint that it must be Hashable. Dictionary is defined as struct Dictionary<Key : Hashable, Value>. Hashable basically means that the type can be represented using an integer. In fact, we can look at exactly what it means if we write Hashable in Xcode and then click on it while holding down the Command Key. This brings us to the definition of Hashable, which has comments that explain that the hash value of two objects that are equal must be the same. This is important to the way that Dictionary is implemented. So, if we want to be able to store our elements as keys in a dictionary, we must also add the Hashable constraint:

Now the compiler is happy and we can start to use our Bag2 struct with any type that is Hashable. We are close to solving our Container problem, but we need a constraint on the type alias of Container, not Container itself. To do that, we can use a where clause.

Generic function

In

Chapter 5, A Modern Paradigm – Closures and Functional Programming, we created a function that helped us find the first number in an array of numbers that passes a test:

This would be great if we only ever dealt with arrays of integers, but clearly it would be helpful to be able to do this with other types. In fact, dare I say, all types? We achieve this very simply by making our function generic. A generic function is declared similar to a normal function, but you include a list of comma-separated placeholders inside angled brackets (<>) at the end of the function name, as shown:

In this function, we have declared a single placeholder called ValueType. Just like with type aliases, we can continue to use this type in our implementation. This will stand in for a single type that will be determined when we go to use the function. You can imagine inserting String or any other type into this code instead of ValueType and it would still work.

We use this function similarly to any other function, as shown:

Here, we have used firstInArray:passingTest: with both an array of strings and an array of numbers. The compiler figures out what type to substitute in for the placeholder based on the variables we pass into the function. In the first case, strings is an array of String. It compares that to [ValueType] and assumes that we want to replace ValueType with String. The same thing happens with our Int array in the second case.

So what happens if the type we use in our closure doesn't match the type of array we pass in?

As you can see, we get an error that the types don't match.

You may have noticed that we have actually used generic functions before. All of the built in functions we looked at in Chapter 5, A Modern Paradigm – Closures and Functional Programming, such as map and filter are generic; they can be used with any type.

We have even experienced generic types before. Arrays and dictionaries are also generic. The Swift team didn't have to write a new implementation of array and dictionary for every type that we might want to use inside the containers; they created them as generic types.

Similar to a generic function, a generic type is defined just like a normal type but it has a list of placeholders at the end of its name. Earlier in this chapter, we created our own containers for strings and integers. Let's make a generic version of these containers, as shown:

This implementation looks similar to our type alias versions, but we are using the ElementType placeholder instead.

While a generic function's placeholders are determined when the function is called, a generic type's placeholders are determined when initializing new instances:

All future interactions with a generic instance must use the same types for its placeholders. This is actually one of the beauties of generics where the compiler does work for us. If we create an instance of one type and accidently try to use it as a different type, the compiler won't let us. This protection does not exist in many other programming languages, including Apple's previous language: Objective-C.

One interesting case to consider is if we try to initialize a bag with an empty array:

As you can see, we get an error that the compiler could not determine the type to assign to our generic placeholder. We can solve this by giving an explicit type to the generic we are assigning it to:

This is great because not only can the compiler determine the generic placeholder types based on the variables we pass to them, it can also determine the type based on how we are using the result.

We have already seen how to use generics in a powerful way. We solved the first problem we discussed in the type alias section about copying and pasting a bunch of implementations for different types. However, we have not yet figured out how to solve the second problem: how do we write a generic function to handle any type of our Container protocol? The answer is that we can use type constraints.

Before we jump right into solving the problem, let's take a look at a simpler form of type constraints.

Let's say that we want to write a function that can determine the index of an instance within an array using an equality check. Our first attempt will probably look similar to the following code:

With this attempt, we get an error that we cannot invoke the equality operator (==). This is because our implementation must work for any possible type that might be assigned to our placeholder. Not every type in Swift can be tested for equality. To fix this problem, we can use a type constraint to tell the compiler that we only want to allow our function to be called with types that support the equality operation. We add type constraints by requiring the placeholder to implement a protocol. In this case, Swift provides a protocol called Equatable, which we can use:

A type constraint looks similar to a type implementing a protocol using a colon (:) after a placeholder name. Now, the compiler is satisfied that every possible type can be compared using the equality operator. If we were to try to call this function with a type that is not equatable, the compiler would produce an error:

This is another case where the compiler can save us from ourselves.

We can also add type constraints to our generic types. For example, if we tried to create a bag with our dictionary implementation without a constraint, we would get an error:

This is because the key of dictionaries has a constraint that it must be Hashable. Dictionary is defined as struct Dictionary<Key : Hashable, Value>. Hashable basically means that the type can be represented using an integer. In fact, we can look at exactly what it means if we write Hashable in Xcode and then click on it while holding down the Command Key. This brings us to the definition of Hashable, which has comments that explain that the hash value of two objects that are equal must be the same. This is important to the way that Dictionary is implemented. So, if we want to be able to store our elements as keys in a dictionary, we must also add the Hashable constraint:

Now the compiler is happy and we can start to use our Bag2 struct with any type that is Hashable. We are close to solving our Container problem, but we need a constraint on the type alias of Container, not Container itself. To do that, we can use a where clause.

Generic type

Similar to a

generic function, a generic type is defined just like a normal type but it has a list of placeholders at the end of its name. Earlier in this chapter, we created our own containers for strings and integers. Let's make a generic version of these containers, as shown:

This implementation looks similar to our type alias versions, but we are using the ElementType placeholder instead.

While a generic function's placeholders are determined when the function is called, a generic type's placeholders are determined when initializing new instances:

All future interactions with a generic instance must use the same types for its placeholders. This is actually one of the beauties of generics where the compiler does work for us. If we create an instance of one type and accidently try to use it as a different type, the compiler won't let us. This protection does not exist in many other programming languages, including Apple's previous language: Objective-C.

One interesting case to consider is if we try to initialize a bag with an empty array:

As you can see, we get an error that the compiler could not determine the type to assign to our generic placeholder. We can solve this by giving an explicit type to the generic we are assigning it to:

This is great because not only can the compiler determine the generic placeholder types based on the variables we pass to them, it can also determine the type based on how we are using the result.

We have already seen how to use generics in a powerful way. We solved the first problem we discussed in the type alias section about copying and pasting a bunch of implementations for different types. However, we have not yet figured out how to solve the second problem: how do we write a generic function to handle any type of our Container protocol? The answer is that we can use type constraints.

Before we jump right into solving the problem, let's take a look at a simpler form of type constraints.

Let's say that we want to write a function that can determine the index of an instance within an array using an equality check. Our first attempt will probably look similar to the following code:

With this attempt, we get an error that we cannot invoke the equality operator (==). This is because our implementation must work for any possible type that might be assigned to our placeholder. Not every type in Swift can be tested for equality. To fix this problem, we can use a type constraint to tell the compiler that we only want to allow our function to be called with types that support the equality operation. We add type constraints by requiring the placeholder to implement a protocol. In this case, Swift provides a protocol called Equatable, which we can use:

A type constraint looks similar to a type implementing a protocol using a colon (:) after a placeholder name. Now, the compiler is satisfied that every possible type can be compared using the equality operator. If we were to try to call this function with a type that is not equatable, the compiler would produce an error:

This is another case where the compiler can save us from ourselves.

We can also add type constraints to our generic types. For example, if we tried to create a bag with our dictionary implementation without a constraint, we would get an error:

This is because the key of dictionaries has a constraint that it must be Hashable. Dictionary is defined as struct Dictionary<Key : Hashable, Value>. Hashable basically means that the type can be represented using an integer. In fact, we can look at exactly what it means if we write Hashable in Xcode and then click on it while holding down the Command Key. This brings us to the definition of Hashable, which has comments that explain that the hash value of two objects that are equal must be the same. This is important to the way that Dictionary is implemented. So, if we want to be able to store our elements as keys in a dictionary, we must also add the Hashable constraint:

Now the compiler is happy and we can start to use our Bag2 struct with any type that is Hashable. We are close to solving our Container problem, but we need a constraint on the type alias of Container, not Container itself. To do that, we can use a where clause.

Type constraints

Before

we jump right into solving the problem, let's take a look at a simpler form of type constraints.

Let's say that we want to write a function that can determine the index of an instance within an array using an equality check. Our first attempt will probably look similar to the following code:

With this attempt, we get an error that we cannot invoke the equality operator (==). This is because our implementation must work for any possible type that might be assigned to our placeholder. Not every type in Swift can be tested for equality. To fix this problem, we can use a type constraint to tell the compiler that we only want to allow our function to be called with types that support the equality operation. We add type constraints by requiring the placeholder to implement a protocol. In this case, Swift provides a protocol called Equatable, which we can use:

A type constraint looks similar to a type implementing a protocol using a colon (:) after a placeholder name. Now, the compiler is satisfied that every possible type can be compared using the equality operator. If we were to try to call this function with a type that is not equatable, the compiler would produce an error:

This is another case where the compiler can save us from ourselves.

We can also add type constraints to our generic types. For example, if we tried to create a bag with our dictionary implementation without a constraint, we would get an error:

This is because the key of dictionaries has a constraint that it must be Hashable. Dictionary is defined as struct Dictionary<Key : Hashable, Value>. Hashable basically means that the type can be represented using an integer. In fact, we can look at exactly what it means if we write Hashable in Xcode and then click on it while holding down the Command Key. This brings us to the definition of Hashable, which has comments that explain that the hash value of two objects that are equal must be the same. This is important to the way that Dictionary is implemented. So, if we want to be able to store our elements as keys in a dictionary, we must also add the Hashable constraint:

Now the compiler is happy and we can start to use our Bag2 struct with any type that is Hashable. We are close to solving our Container problem, but we need a constraint on the type alias of Container, not Container itself. To do that, we can use a where clause.

Protocol constraints

Let's say that we

want to write a function that can determine the index of an instance within an array using an equality check. Our first attempt will probably look similar to the following code:

With this attempt, we get an error that we cannot invoke the equality operator (==). This is because our implementation must work for any possible type that might be assigned to our placeholder. Not every type in Swift can be tested for equality. To fix this problem, we can use a type constraint to tell the compiler that we only want to allow our function to be called with types that support the equality operation. We add type constraints by requiring the placeholder to implement a protocol. In this case, Swift provides a protocol called Equatable, which we can use:

A type constraint looks similar to a type implementing a protocol using a colon (:) after a placeholder name. Now, the compiler is satisfied that every possible type can be compared using the equality operator. If we were to try to call this function with a type that is not equatable, the compiler would produce an error:

This is another case where the compiler can save us from ourselves.

We can also add type constraints to our generic types. For example, if we tried to create a bag with our dictionary implementation without a constraint, we would get an error:

This is because the key of dictionaries has a constraint that it must be Hashable. Dictionary is defined as struct Dictionary<Key : Hashable, Value>. Hashable basically means that the type can be represented using an integer. In fact, we can look at exactly what it means if we write Hashable in Xcode and then click on it while holding down the Command Key. This brings us to the definition of Hashable, which has comments that explain that the hash value of two objects that are equal must be the same. This is important to the way that Dictionary is implemented. So, if we want to be able to store our elements as keys in a dictionary, we must also add the Hashable constraint:

Now the compiler is happy and we can start to use our Bag2 struct with any type that is Hashable. We are close to solving our Container problem, but we need a constraint on the type alias of Container, not Container itself. To do that, we can use a where clause.

Where clauses for protocols

You can
Where clauses for equality

If we want to write a

The two main generics that we will probably want to extend are arrays and dictionaries. These are the two most prominent containers provided by Swift and are used in virtually every app. Extending a generic type is simple once you understand that an extension itself does not need to be generic.

Knowing that an array is declared as struct Array<Element>, your first instinct to extend an array might look something similar to this:

However, as you can see, you would get an error. Instead, you can simply leave out the placeholder specification and still use the Element placeholder inside your implementations. Your other instinct might be to declare Element as a placeholder for your individual methods:

This is more dangerous because the compiler doesn't detect an error. This is wrong because you are actually declaring a new placeholder Element to be used within the method. This new Element has nothing to do with the Element defined in Array itself. For example, you might get a confusing error if you tried to compare a parameter to the method to an element of the Array:

This is because the Element defined in Array cannot be guaranteed to be the exact same type as the new Element defined in addElement:. You are free to declare additional placeholders in methods on generic types, but it is best to give them unique names so that they don't hide the type's version of the placeholder.

Now that we understand this, let's add an extension to the array that allows us to test if it contains an element passing a test:

As you can see, we continue to use the placeholder Element within our extension. This allows us to call the passed in test closure for each element in the array. Now, what if we want to be able to add a method that will check if an element exists using the equality operator? The problem that we will run into is that array does not place a type constraint on Element requiring it to be Equatable. To do this, we can add an extra constraint to our extension.

We first discussed how we can extend existing types in Chapter 3, One Piece at a Time – Types, Scopes, and Projects. In Swift 2, Apple added the ability to extend protocols. This has some fascinating implications, but before we dive into those, let's take a look at an example of adding a method to the Comparable protocol:

extension Comparable {
    func isBetween(a: Self, b: Self) -> Bool {
        return a < self && self < b
    }
}

This adds a method to all types that implement the Comparable. This means that it will now be available on any of the built-in types that are comparable and any of our own types that are comparable:

This is a really powerful tool. In fact, this is how the Swift team implemented many of the functional methods we saw in Chapter 5, A Modern Paradigm – Closures and Functional Programming. They did not have to implement the map method on arrays, dictionaries, or on any other sequence that should be mappable; instead, they implemented it directly on SequenceType.

This shows that similarly, protocol extensions can be used for inheritance, and it can also be applied to both classes and structures and types can also inherit this functionality from multiple different protocols because there is no limit to the number of protocols a type can implement. However, there are two major differences between the two.

First, types cannot inherit stored properties from protocols, because extensions cannot define them. Protocols can define read only properties but every instance will have to redeclare them as properties:

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

Second, method overriding does not work in the same way with protocol extensions. With protocols, Swift does not intelligently figure out which version of a method to call based on the actual type of an instance. With class inheritance, Swift will call the version of a method that is most directly associated with the instance. Remember, when we called clean on an instance of our House subclass in Chapter 3, One Piece at a Time – Types, Scopes, and Projects, it calls the overriding version of clean, as shown:

class Building {
    // ...

    func clean() {
        print(
            "Scrub \(self.squareFootage) square feet of floors"
        )
    }
}

class House: Building {
    // ...

    override func clean() {
        print("Make \(self.numberOfBedrooms) beds")
        print("Clean \(self.numberOfBathrooms) bathrooms")
    }
}

let building: Building = House(
    squareFootage: 800,
    numberOfBedrooms: 2,
    numberOfBathrooms: 1
)
building.clean()
// Make 2 beds
// Clean 1 bathroom

Here, even though the building variable is defined as a Building, it is in fact a house; so Swift will call the house's version of clean. The contrast with protocol extensions is that it will call the version of the method that is defined by the exact type the variable is declared as:

When we call clean on the house variable which is of type House, it calls the house version; however, when we cast the variable to a Building and then call it, it calls the building version.

All of this shows that it can be hard to choose between using structures and protocols or class inheritance. We will look at the last piece of that consideration in the next chapter on memory management, so we will be able to make a fully informed decision when moving forward.

Now that we have looked at the features available to us with generics and protocols, let's take this opportunity to explore some more advanced ways protocols and generics are used in Swift.

Adding methods to all forms of a generic

Knowing that

an array is declared as struct Array<Element>, your first instinct to extend an array might look something similar to this:

However, as you can see, you would get an error. Instead, you can simply leave out the placeholder specification and still use the Element placeholder inside your implementations. Your other instinct might be to declare Element as a placeholder for your individual methods:

This is more dangerous because the compiler doesn't detect an error. This is wrong because you are actually declaring a new placeholder Element to be used within the method. This new Element has nothing to do with the Element defined in Array itself. For example, you might get a confusing error if you tried to compare a parameter to the method to an element of the Array:

This is because the Element defined in Array cannot be guaranteed to be the exact same type as the new Element defined in addElement:. You are free to declare additional placeholders in methods on generic types, but it is best to give them unique names so that they don't hide the type's version of the placeholder.

Now that we understand this, let's add an extension to the array that allows us to test if it contains an element passing a test:

As you can see, we continue to use the placeholder Element within our extension. This allows us to call the passed in test closure for each element in the array. Now, what if we want to be able to add a method that will check if an element exists using the equality operator? The problem that we will run into is that array does not place a type constraint on Element requiring it to be Equatable. To do this, we can add an extra constraint to our extension.

We first discussed how we can extend existing types in Chapter 3, One Piece at a Time – Types, Scopes, and Projects. In Swift 2, Apple added the ability to extend protocols. This has some fascinating implications, but before we dive into those, let's take a look at an example of adding a method to the Comparable protocol:

extension Comparable {
    func isBetween(a: Self, b: Self) -> Bool {
        return a < self && self < b
    }
}

This adds a method to all types that implement the Comparable. This means that it will now be available on any of the built-in types that are comparable and any of our own types that are comparable:

This is a really powerful tool. In fact, this is how the Swift team implemented many of the functional methods we saw in Chapter 5, A Modern Paradigm – Closures and Functional Programming. They did not have to implement the map method on arrays, dictionaries, or on any other sequence that should be mappable; instead, they implemented it directly on SequenceType.

This shows that similarly, protocol extensions can be used for inheritance, and it can also be applied to both classes and structures and types can also inherit this functionality from multiple different protocols because there is no limit to the number of protocols a type can implement. However, there are two major differences between the two.

First, types cannot inherit stored properties from protocols, because extensions cannot define them. Protocols can define read only properties but every instance will have to redeclare them as properties:

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

Second, method overriding does not work in the same way with protocol extensions. With protocols, Swift does not intelligently figure out which version of a method to call based on the actual type of an instance. With class inheritance, Swift will call the version of a method that is most directly associated with the instance. Remember, when we called clean on an instance of our House subclass in Chapter 3, One Piece at a Time – Types, Scopes, and Projects, it calls the overriding version of clean, as shown:

class Building {
    // ...

    func clean() {
        print(
            "Scrub \(self.squareFootage) square feet of floors"
        )
    }
}

class House: Building {
    // ...

    override func clean() {
        print("Make \(self.numberOfBedrooms) beds")
        print("Clean \(self.numberOfBathrooms) bathrooms")
    }
}

let building: Building = House(
    squareFootage: 800,
    numberOfBedrooms: 2,
    numberOfBathrooms: 1
)
building.clean()
// Make 2 beds
// Clean 1 bathroom

Here, even though the building variable is defined as a Building, it is in fact a house; so Swift will call the house's version of clean. The contrast with protocol extensions is that it will call the version of the method that is defined by the exact type the variable is declared as:

When we call clean on the house variable which is of type House, it calls the house version; however, when we cast the variable to a Building and then call it, it calls the building version.

All of this shows that it can be hard to choose between using structures and protocols or class inheritance. We will look at the last piece of that consideration in the next chapter on memory management, so we will be able to make a fully informed decision when moving forward.

Now that we have looked at the features available to us with generics and protocols, let's take this opportunity to explore some more advanced ways protocols and generics are used in Swift.

Adding methods to only certain instances of a generic

A

We first discussed how we can extend existing types in Chapter 3, One Piece at a Time – Types, Scopes, and Projects. In Swift 2, Apple added the ability to extend protocols. This has some fascinating implications, but before we dive into those, let's take a look at an example of adding a method to the Comparable protocol:

extension Comparable {
    func isBetween(a: Self, b: Self) -> Bool {
        return a < self && self < b
    }
}

This adds a method to all types that implement the Comparable. This means that it will now be available on any of the built-in types that are comparable and any of our own types that are comparable:

This is a really powerful tool. In fact, this is how the Swift team implemented many of the functional methods we saw in Chapter 5, A Modern Paradigm – Closures and Functional Programming. They did not have to implement the map method on arrays, dictionaries, or on any other sequence that should be mappable; instead, they implemented it directly on SequenceType.

This shows that similarly, protocol extensions can be used for inheritance, and it can also be applied to both classes and structures and types can also inherit this functionality from multiple different protocols because there is no limit to the number of protocols a type can implement. However, there are two major differences between the two.

First, types cannot inherit stored properties from protocols, because extensions cannot define them. Protocols can define read only properties but every instance will have to redeclare them as properties:

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

Second, method overriding does not work in the same way with protocol extensions. With protocols, Swift does not intelligently figure out which version of a method to call based on the actual type of an instance. With class inheritance, Swift will call the version of a method that is most directly associated with the instance. Remember, when we called clean on an instance of our House subclass in Chapter 3, One Piece at a Time – Types, Scopes, and Projects, it calls the overriding version of clean, as shown:

class Building {
    // ...

    func clean() {
        print(
            "Scrub \(self.squareFootage) square feet of floors"
        )
    }
}

class House: Building {
    // ...

    override func clean() {
        print("Make \(self.numberOfBedrooms) beds")
        print("Clean \(self.numberOfBathrooms) bathrooms")
    }
}

let building: Building = House(
    squareFootage: 800,
    numberOfBedrooms: 2,
    numberOfBathrooms: 1
)
building.clean()
// Make 2 beds
// Clean 1 bathroom

Here, even though the building variable is defined as a Building, it is in fact a house; so Swift will call the house's version of clean. The contrast with protocol extensions is that it will call the version of the method that is defined by the exact type the variable is declared as:

When we call clean on the house variable which is of type House, it calls the house version; however, when we cast the variable to a Building and then call it, it calls the building version.

All of this shows that it can be hard to choose between using structures and protocols or class inheritance. We will look at the last piece of that consideration in the next chapter on memory management, so we will be able to make a fully informed decision when moving forward.

Now that we have looked at the features available to us with generics and protocols, let's take this opportunity to explore some more advanced ways protocols and generics are used in Swift.

Extending protocols

We first discussed

how we can extend existing types in Chapter 3, One Piece at a Time – Types, Scopes, and Projects. In Swift 2, Apple added the ability to extend protocols. This has some fascinating implications, but before we dive into those, let's take a look at an example of adding a method to the Comparable protocol:

extension Comparable {
    func isBetween(a: Self, b: Self) -> Bool {
        return a < self && self < b
    }
}

This adds a method to all types that implement the Comparable. This means that it will now be available on any of the built-in types that are comparable and any of our own types that are comparable:

This is a really powerful tool. In fact, this is how the Swift team implemented many of the functional methods we saw in Chapter 5, A Modern Paradigm – Closures and Functional Programming. They did not have to implement the map method on arrays, dictionaries, or on any other sequence that should be mappable; instead, they implemented it directly on SequenceType.

This shows that similarly, protocol extensions can be used for inheritance, and it can also be applied to both classes and structures and types can also inherit this functionality from multiple different protocols because there is no limit to the number of protocols a type can implement. However, there are two major differences between the two.

First, types cannot inherit stored properties from protocols, because extensions cannot define them. Protocols can define read only properties but every instance will have to redeclare them as properties:

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

Second, method overriding does not work in the same way with protocol extensions. With protocols, Swift does not intelligently figure out which version of a method to call based on the actual type of an instance. With class inheritance, Swift will call the version of a method that is most directly associated with the instance. Remember, when we called clean on an instance of our House subclass in Chapter 3, One Piece at a Time – Types, Scopes, and Projects, it calls the overriding version of clean, as shown:

class Building {
    // ...

    func clean() {
        print(
            "Scrub \(self.squareFootage) square feet of floors"
        )
    }
}

class House: Building {
    // ...

    override func clean() {
        print("Make \(self.numberOfBedrooms) beds")
        print("Clean \(self.numberOfBathrooms) bathrooms")
    }
}

let building: Building = House(
    squareFootage: 800,
    numberOfBedrooms: 2,
    numberOfBathrooms: 1
)
building.clean()
// Make 2 beds
// Clean 1 bathroom

Here, even though the building variable is defined as a Building, it is in fact a house; so Swift will call the house's version of clean. The contrast with protocol extensions is that it will call the version of the method that is defined by the exact type the variable is declared as:

When we call clean on the house variable which is of type House, it calls the house version; however, when we cast the variable to a Building and then call it, it calls the building version.

All of this shows that it can be hard to choose between using structures and protocols or class inheritance. We will look at the last piece of that consideration in the next chapter on memory management, so we will be able to make a fully informed decision when moving forward.

Now that we have looked at the features available to us with generics and protocols, let's take this opportunity to explore some more advanced ways protocols and generics are used in Swift.

One cool part of Swift is generators and sequences. They provide an easy way to iterate over a list of values. Ultimately, they boil down to two different protocols: GeneratorType and SequenceType. If you implement the SequenceType protocol in your custom types, it allows you to use the for-in loop over an instance of your type. In this section, we will look at how we can do that.

The most critical part of this is the GeneratorType protocol. Essentially, a generator is an object that you can repeatedly ask for the next object in a series until there are no objects left. Most of the time you can simply use an array for this, but it is not always the best solution. For example, you can even make a generator that is infinite.

There is a famous infinite series of numbers called the Fibonacci sequence, where every number in the series is the sum of the two previous numbers. This is especially famous because it is found all over nature from the number of bees in a nest to the most pleasing aspect ratio of a rectangle to look at. Let's create an infinite generator that will produce this series.

We start by creating a structure that implements the GeneratorType protocol. The protocol is made up of two pieces. First, it has a type alias for the type of elements in the sequence and second, it has a mutating method called next that returns the next object in the sequence.

The implementation looks similar to this:

We defined a property called values that is a tuple representing the previous two values in the sequence. We update values and return the first element of the tuple each time next is called. This means that there will be no end to the sequence.

We can use this generator on its own by instantiating it and then repeatedly calling next inside a while loop:

We need to set up some sort of a condition so that the loop doesn't go on forever. In this case, we break out of the loop once the numbers get above 10. However, this code is pretty ugly, so Swift also defines the protocol called SequenceType to clean it up.

SequenceType is another protocol that is defined as having a type alias for a GeneratorType and a method called generate that returns a new generator of that type. We could declare a simple sequence for our FibonacciGenerator, as follows:

Every for-in loop operates on the SequenceType protocol, so now we can use a for-in loop on our FibonacciSequence:

This is pretty cool; we can easily iterate over the Fibonacci sequence in a very readable way. It is much easier to understand the preceding code than it would be to understand a complicated while loop that has to calculate the next value of the sequence each time. Imagine all of the other type of sequences we can design such as prime numbers, random name generators, and so on.

However, it is not always ideal to have to define two different types to create a single sequence. To fix this, we can use generics. Swift provides a generic type called AnyGenerator with a companion function called anyGenerator:. This function takes a closure and returns a generator that uses the closure as its next method. This means that we don't have to explicitly create a generator ourselves; instead we can use anyGenerator: directly in a sequence:

In this version of FibonacciSequence, we create a new generator every time generate is called that takes a closure that does the same thing that our original FibonacciGenerator was doing. We declare the values variable outside of the closure so that we can use it to store the state between calls to the closure. If your generator is simple and doesn't require a complicated state, using the AnyGenerator generic is a great way to go.

Now let's use this FibonacciSequence to solve the kind of math problem that computers are great at.

What if we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.

Generators

The most

critical part of this is the GeneratorType protocol. Essentially, a generator is an object that you can repeatedly ask for the next object in a series until there are no objects left. Most of the time you can simply use an array for this, but it is not always the best solution. For example, you can even make a generator that is infinite.

There is a famous infinite series of numbers called the Fibonacci sequence, where every number in the series is the sum of the two previous numbers. This is especially famous because it is found all over nature from the number of bees in a nest to the most pleasing aspect ratio of a rectangle to look at. Let's create an infinite generator that will produce this series.

We start by creating a structure that implements the GeneratorType protocol. The protocol is made up of two pieces. First, it has a type alias for the type of elements in the sequence and second, it has a mutating method called next that returns the next object in the sequence.

The implementation looks similar to this:

We defined a property called values that is a tuple representing the previous two values in the sequence. We update values and return the first element of the tuple each time next is called. This means that there will be no end to the sequence.

We can use this generator on its own by instantiating it and then repeatedly calling next inside a while loop:

We need to set up some sort of a condition so that the loop doesn't go on forever. In this case, we break out of the loop once the numbers get above 10. However, this code is pretty ugly, so Swift also defines the protocol called SequenceType to clean it up.

SequenceType is another protocol that is defined as having a type alias for a GeneratorType and a method called generate that returns a new generator of that type. We could declare a simple sequence for our FibonacciGenerator, as follows:

Every for-in loop operates on the SequenceType protocol, so now we can use a for-in loop on our FibonacciSequence:

This is pretty cool; we can easily iterate over the Fibonacci sequence in a very readable way. It is much easier to understand the preceding code than it would be to understand a complicated while loop that has to calculate the next value of the sequence each time. Imagine all of the other type of sequences we can design such as prime numbers, random name generators, and so on.

However, it is not always ideal to have to define two different types to create a single sequence. To fix this, we can use generics. Swift provides a generic type called AnyGenerator with a companion function called anyGenerator:. This function takes a closure and returns a generator that uses the closure as its next method. This means that we don't have to explicitly create a generator ourselves; instead we can use anyGenerator: directly in a sequence:

In this version of FibonacciSequence, we create a new generator every time generate is called that takes a closure that does the same thing that our original FibonacciGenerator was doing. We declare the values variable outside of the closure so that we can use it to store the state between calls to the closure. If your generator is simple and doesn't require a complicated state, using the AnyGenerator generic is a great way to go.

Now let's use this FibonacciSequence to solve the kind of math problem that computers are great at.

What if we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.

Sequences

SequenceType is

another protocol that is defined as having a type alias for a GeneratorType and a method called generate that returns a new generator of that type. We could declare a simple sequence for our FibonacciGenerator, as follows:

Every for-in loop operates on the SequenceType protocol, so now we can use a for-in loop on our FibonacciSequence:

This is pretty cool; we can easily iterate over the Fibonacci sequence in a very readable way. It is much easier to understand the preceding code than it would be to understand a complicated while loop that has to calculate the next value of the sequence each time. Imagine all of the other type of sequences we can design such as prime numbers, random name generators, and so on.

However, it is not always ideal to have to define two different types to create a single sequence. To fix this, we can use generics. Swift provides a generic type called AnyGenerator with a companion function called anyGenerator:. This function takes a closure and returns a generator that uses the closure as its next method. This means that we don't have to explicitly create a generator ourselves; instead we can use anyGenerator: directly in a sequence:

In this version of FibonacciSequence, we create a new generator every time generate is called that takes a closure that does the same thing that our original FibonacciGenerator was doing. We declare the values variable outside of the closure so that we can use it to store the state between calls to the closure. If your generator is simple and doesn't require a complicated state, using the AnyGenerator generic is a great way to go.

Now let's use this FibonacciSequence to solve the kind of math problem that computers are great at.

What if we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.

Product of Fibonacci numbers under 50

What if

we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.

 

When using an app, there is nothing worse than it being slow and unresponsive. Computer users have come to expect every piece of software to respond immediately to every interaction. Even the most feature-rich app will be ruined if it is unpleasant to use because it doesn't manage the device resources effectively. Also, with the growing popularity of mobile computers and devices, it is more important than ever to write software that uses battery power efficiently. One of the aspects of writing software that has the largest impact on both responsiveness and battery power is memory management.

In this chapter, we will discuss techniques specific to Swift that allow us to manage memory in order to ensure that our code remains responsive and minimizes its effect on battery life and other apps. We will do so by covering the following topics:

Before we start looking at the code, we need to understand in some detail how data is represented in a computer. The common cliché is that all data in a computer is in 1s and 0s. This is true, but not so important when talking about memory management. Instead, we are concerned about where the data is stored. All computers, whether a desktop, laptop, tablet, or phone, store data in two places.

The first place we normally think of is the file system. It is stored on a dedicated piece of hardware; this is called a hard disk drive in many computers, but more recently, some computers have started to use solid-state drives. The other thing we hear about when buying computers is the amount of "memory" it has. Computer memory comes in "sticks" which hold less information than normal drives. All data, even if primarily stored on the Internet somewhere, must be loaded into the computer's memory so that we can interact with it.

Let's take a look at what that means for us as programmers.

Memory is a little more complex than the file system. It is designed to store the necessary data, temporarily for the software running currently. Unlike with a file system, all memory is lost as soon as you turn off your device. The analogy is similar to how we humans have short-term and long-term memory. While we are having a conversation or thinking about something, we have a certain subset of the information we are actively thinking about and the rest is in our long-term memory. In order to actively think about something, we have to recall it from our long-term memory into our short-term memory.

Memory is quick to access, but it is much more expensive. When computers start to act abnormally slow, it is commonly because it is very close to using up all of its memory. This is because the operating system will automatically start using the file system as a backup when memory is low. Information that is meant for short-term storage is automatically written to the file system instead, making it much slower to access again.

This is similar to how we humans have a problem processing too much information at once. If we try to add two 20-digit numbers in our head, it is going to take us a long time or simply be impossible. Instead, we often write out the partial solution on paper, as we go along. In this case, the paper is acting as our file system. It would be faster if we could just remember everything instead of taking the time to write it down and read it back, but we simply can't process that much information at one time.

This is important to consider when programming because we want to reduce the amount of memory that we use at any given time. Using a lot of memory doesn't only negatively affect our own software; it can negatively affect the entire computer's performance. Also, when the operating system has to resort to using the file system, the extra processing and extra access to a second piece of hardware causes more power usage.

Now that we understand our goal, we can start discussing how we manage memory better in Swift.

All variables and constants in Swift are stored in memory. In fact, unless you explicitly write data to the file system, everything you create is going to be in memory. In Swift, there are two different categories of types. These two categories are value types and reference types. The only way in which they differ is in the way they behave when they get assigned to new variables, passed into methods, or captured in closures. Essentially, they only differ when you try to assign a new variable or constant to the value of an existing variable or constant.

A value type is always copied when being assigned somewhere new while a reference type is not. Before we look at exactly what that means in more detail, let's go over how we determine if a type is a value type or a reference type.

When a value type is reassigned, it is copied so that afterwards each variable or constant holds a distinct value that can be changed independently. Let's take a look at a simple example using a string:

As you can see, when value2 is set to value1 a copy gets created. This is so that when we append " World!" to value1, value2 remains unchanged, as "Hello". We can visualize them as two completely separate entities:

Behavior on assignment

On the other hand, let's take a look at what happens with a reference type:

As you can see, when we changed the name of reference1, reference2 was also changed. So why is this? As the name implies, reference types are simply references to an instance. When you assign a reference to another variable or constant, both are actually referring to the exact same instance. We can visualize it as two separate objects referencing the same instance:

Behavior on assignment

In the real world, this would be like two kids sharing a toy. Both can play with the toy but if one breaks the toy, it is broken for both kids.

However, it is important to realize that if you assign a reference type to a new value, it does not change the value it was originally referencing:

As you can see, we assigned reference2 to an entirely different Person instance, so they can now be manipulated independently. We can then visualize this as two separate references on two separate instances, as shown in the following image:

Behavior on assignment

This will be like buying a new toy for one of the kids.

This shows you that a reference type is actually a special version of a value type. The difference is that a reference type is not itself an instance of any type. It is simply a way to refer to another instance, sort of like a placeholder. You can copy the reference so that you have two variables referencing the same instance, or you can give a variable a completely new reference to a new instance. With reference types, there is an extra layer of indirection based on sharing instances between multiple variables.

Now that we know this, the simplest way to verify if a type is a value type or a reference type is to check its behavior when being assigned. If the second value is changed when you modify the first value, it means that the type you are testing is a reference type.

Another place where the behavior of a value type differs from a reference type is when passing them into functions and methods. However, the behavior is very simple to remember if you look at passing a variable or constant into a function as just another assignment. This means that when you pass a value type into a function, it is copied while a reference type still shares the same instance:

Here we have defined a function that takes both a reference type: Person and a value type: String. When we update the Person type within the function, the person we passed in is also changed:

However, when we change the string within the function, the String passed into it remains unchanged.

The place where things get a little more complicated is with inout parameters. An inout parameter is actually a reference to the passed-in instance. This means that, it will treat a value type as if it were a reference type:

As you can see, when we changed the inout version of string within the function, it also changed the someString variable outside of the function just as if it were a reference type.

If we remember that a reference type is just a special version of a value type where the value is a reference, we can infer what will be possible with an inout version of a reference type. When we define an inout reference type, we actually have a reference to a reference; this reference is then the one that is pointing to a reference. We can visualize the difference between an inout value type and an inout reference type as shown:

Behavior on input

If we simply change the value of this variable, we will get the same behavior as if it were not an inout parameter. However, we can also change where the inner reference is referring to by declaring it as an inout parameter:

We start by creating a second reference: person2 to the same instance as the person variable that currently has the name "Jamison" from before. After this, we pass the original person variable into our updatePerson: method and have this:

Behavior on input

In this method, we first change the name of the existing person to a new name. We can see in the output that the name of person2 has also changed, because both insidePerson inside the function and person2 are still referencing the same instance:

Behavior on input

However, we then also assign insidePerson to a completely new instance of the Person reference type. This results in person and person2 outside of the function pointing at two completely different instances of Person leaving the name of person2 to be "New Name" and updating the name of person to "New Person":

Behavior on input

Here, by defining insidePerson as an inout parameter, we were able to change where the passed-in variable was referencing. It can help us to visualize all the different types as one type pointing to another.

At any point, any of these arrows can be pointed at something new using an assignment and the instance can always be accessed through the references.

The last behavior we have to worry about is when variables are captured within closures. This is what we did not cover about closures in Chapter 5, A Modern Paradigm – Closures and Functional Programming. Closures can actually use the variables that were defined in the same scope as the closure itself:

var nameToPrint = "Kai"
var printName = {
    print(nameToPrint)
}
printName() // "Kai"

This is very different from normal parameters that we have seen before. We actually do not specify nameToPrint as a parameter, nor do we pass it in when calling the method. Instead, the closure captures the nameToPrint variable that is defined before it. These types of captures act similarly to inout parameters in functions.

When a value type is captured, it can be changed and it will change the original value as well:

var outsideName = "Kai"
var setName = {
    outsideName = "New Name"
}
print(outsideName) // "Kai"
setName()
print(outsideName) // "New Name"

As you can see, outsideName was changed after the closure was called. This is exactly like an inout parameter.

When a reference type is captured, any changes will also be applied to the outside version of the variable:

var outsidePerson = Person(name: "Kai")
var setPersonName = {
    outsidePerson.name = "New Name"
}
print(outsidePerson.name) // "Kai"
setPersonName()
print(outsidePerson.name) // "New Name"

This is also exactly like an inout parameter.

The other part of closure capture that we need to keep in mind is that changing the captured value after the closure is defined will still affect the value within the closure. We can take advantage of this to use the printName closure we defined in the preceding section to print any name:

nameToPrint = "Kai"
printName() // Kai
nameToPrint = "New Name"
printName() // "New Name"

As you can see, we can change what printName prints out by changing the value of nameToPrint. This behavior is actually very hard to track down when it happens accidently, so it is usually a good idea to avoid capturing variables in closures whenever possible. In this case, we are taking advantage of the behavior, but more often than not, it will cause bugs. Here, it would be better to pass what we want to print as an argument.

Another way to avoid this behavior is to use a feature called capture lists. With this, you can specify the variables that you want to capture by copying them:

A capture list is defined at the beginning of a closure before any parameter. It is a comma-separated list of all the variables being captured, which we want to copy within square brackets. In this case, we requested nameToPrint to be copied, so when we change it later, it does not affect the value that is printed out. We will see more advanced uses of capture lists later in this chapter.

Determining value type or reference type

A value type

When a value type is reassigned, it is copied so that afterwards each variable or constant holds a distinct value that can be changed independently. Let's take a look at a simple example using a string:

As you can see, when value2 is set to value1 a copy gets created. This is so that when we append " World!" to value1, value2 remains unchanged, as "Hello". We can visualize them as two completely separate entities:

Behavior on assignment

On the other hand, let's take a look at what happens with a reference type:

As you can see, when we changed the name of reference1, reference2 was also changed. So why is this? As the name implies, reference types are simply references to an instance. When you assign a reference to another variable or constant, both are actually referring to the exact same instance. We can visualize it as two separate objects referencing the same instance:

Behavior on assignment

In the real world, this would be like two kids sharing a toy. Both can play with the toy but if one breaks the toy, it is broken for both kids.

However, it is important to realize that if you assign a reference type to a new value, it does not change the value it was originally referencing:

As you can see, we assigned reference2 to an entirely different Person instance, so they can now be manipulated independently. We can then visualize this as two separate references on two separate instances, as shown in the following image:

Behavior on assignment

This will be like buying a new toy for one of the kids.

This shows you that a reference type is actually a special version of a value type. The difference is that a reference type is not itself an instance of any type. It is simply a way to refer to another instance, sort of like a placeholder. You can copy the reference so that you have two variables referencing the same instance, or you can give a variable a completely new reference to a new instance. With reference types, there is an extra layer of indirection based on sharing instances between multiple variables.

Now that we know this, the simplest way to verify if a type is a value type or a reference type is to check its behavior when being assigned. If the second value is changed when you modify the first value, it means that the type you are testing is a reference type.

Another place where the behavior of a value type differs from a reference type is when passing them into functions and methods. However, the behavior is very simple to remember if you look at passing a variable or constant into a function as just another assignment. This means that when you pass a value type into a function, it is copied while a reference type still shares the same instance:

Here we have defined a function that takes both a reference type: Person and a value type: String. When we update the Person type within the function, the person we passed in is also changed:

However, when we change the string within the function, the String passed into it remains unchanged.

The place where things get a little more complicated is with inout parameters. An inout parameter is actually a reference to the passed-in instance. This means that, it will treat a value type as if it were a reference type:

As you can see, when we changed the inout version of string within the function, it also changed the someString variable outside of the function just as if it were a reference type.

If we remember that a reference type is just a special version of a value type where the value is a reference, we can infer what will be possible with an inout version of a reference type. When we define an inout reference type, we actually have a reference to a reference; this reference is then the one that is pointing to a reference. We can visualize the difference between an inout value type and an inout reference type as shown:

Behavior on input

If we simply change the value of this variable, we will get the same behavior as if it were not an inout parameter. However, we can also change where the inner reference is referring to by declaring it as an inout parameter:

We start by creating a second reference: person2 to the same instance as the person variable that currently has the name "Jamison" from before. After this, we pass the original person variable into our updatePerson: method and have this:

Behavior on input

In this method, we first change the name of the existing person to a new name. We can see in the output that the name of person2 has also changed, because both insidePerson inside the function and person2 are still referencing the same instance:

Behavior on input

However, we then also assign insidePerson to a completely new instance of the Person reference type. This results in person and person2 outside of the function pointing at two completely different instances of Person leaving the name of person2 to be "New Name" and updating the name of person to "New Person":

Behavior on input

Here, by defining insidePerson as an inout parameter, we were able to change where the passed-in variable was referencing. It can help us to visualize all the different types as one type pointing to another.

At any point, any of these arrows can be pointed at something new using an assignment and the instance can always be accessed through the references.

The last behavior we have to worry about is when variables are captured within closures. This is what we did not cover about closures in Chapter 5, A Modern Paradigm – Closures and Functional Programming. Closures can actually use the variables that were defined in the same scope as the closure itself:

var nameToPrint = "Kai"
var printName = {
    print(nameToPrint)
}
printName() // "Kai"

This is very different from normal parameters that we have seen before. We actually do not specify nameToPrint as a parameter, nor do we pass it in when calling the method. Instead, the closure captures the nameToPrint variable that is defined before it. These types of captures act similarly to inout parameters in functions.

When a value type is captured, it can be changed and it will change the original value as well:

var outsideName = "Kai"
var setName = {
    outsideName = "New Name"
}
print(outsideName) // "Kai"
setName()
print(outsideName) // "New Name"

As you can see, outsideName was changed after the closure was called. This is exactly like an inout parameter.

When a reference type is captured, any changes will also be applied to the outside version of the variable:

var outsidePerson = Person(name: "Kai")
var setPersonName = {
    outsidePerson.name = "New Name"
}
print(outsidePerson.name) // "Kai"
setPersonName()
print(outsidePerson.name) // "New Name"

This is also exactly like an inout parameter.

The other part of closure capture that we need to keep in mind is that changing the captured value after the closure is defined will still affect the value within the closure. We can take advantage of this to use the printName closure we defined in the preceding section to print any name:

nameToPrint = "Kai"
printName() // Kai
nameToPrint = "New Name"
printName() // "New Name"

As you can see, we can change what printName prints out by changing the value of nameToPrint. This behavior is actually very hard to track down when it happens accidently, so it is usually a good idea to avoid capturing variables in closures whenever possible. In this case, we are taking advantage of the behavior, but more often than not, it will cause bugs. Here, it would be better to pass what we want to print as an argument.

Another way to avoid this behavior is to use a feature called capture lists. With this, you can specify the variables that you want to capture by copying them:

A capture list is defined at the beginning of a closure before any parameter. It is a comma-separated list of all the variables being captured, which we want to copy within square brackets. In this case, we requested nameToPrint to be copied, so when we change it later, it does not affect the value that is printed out. We will see more advanced uses of capture lists later in this chapter.

Behavior on assignment

When

a value type is reassigned, it is copied so that afterwards each variable or constant holds a distinct value that can be changed independently. Let's take a look at a simple example using a string:

As you can see, when value2 is set to value1 a copy gets created. This is so that when we append " World!" to value1, value2 remains unchanged, as "Hello". We can visualize them as two completely separate entities:

Behavior on assignment

On the other hand, let's take a look at what happens with a reference type:

As you can see, when we changed the name of reference1, reference2 was also changed. So why is this? As the name implies, reference types are simply references to an instance. When you assign a reference to another variable or constant, both are actually referring to the exact same instance. We can visualize it as two separate objects referencing the same instance:

Behavior on assignment

In the real world, this would be like two kids sharing a toy. Both can play with the toy but if one breaks the toy, it is broken for both kids.

However, it is important to realize that if you assign a reference type to a new value, it does not change the value it was originally referencing:

As you can see, we assigned reference2 to an entirely different Person instance, so they can now be manipulated independently. We can then visualize this as two separate references on two separate instances, as shown in the following image:

Behavior on assignment

This will be like buying a new toy for one of the kids.

This shows you that a reference type is actually a special version of a value type. The difference is that a reference type is not itself an instance of any type. It is simply a way to refer to another instance, sort of like a placeholder. You can copy the reference so that you have two variables referencing the same instance, or you can give a variable a completely new reference to a new instance. With reference types, there is an extra layer of indirection based on sharing instances between multiple variables.

Now that we know this, the simplest way to verify if a type is a value type or a reference type is to check its behavior when being assigned. If the second value is changed when you modify the first value, it means that the type you are testing is a reference type.

Another place where the behavior of a value type differs from a reference type is when passing them into functions and methods. However, the behavior is very simple to remember if you look at passing a variable or constant into a function as just another assignment. This means that when you pass a value type into a function, it is copied while a reference type still shares the same instance:

Here we have defined a function that takes both a reference type: Person and a value type: String. When we update the Person type within the function, the person we passed in is also changed:

However, when we change the string within the function, the String passed into it remains unchanged.

The place where things get a little more complicated is with inout parameters. An inout parameter is actually a reference to the passed-in instance. This means that, it will treat a value type as if it were a reference type:

As you can see, when we changed the inout version of string within the function, it also changed the someString variable outside of the function just as if it were a reference type.

If we remember that a reference type is just a special version of a value type where the value is a reference, we can infer what will be possible with an inout version of a reference type. When we define an inout reference type, we actually have a reference to a reference; this reference is then the one that is pointing to a reference. We can visualize the difference between an inout value type and an inout reference type as shown:

Behavior on input

If we simply change the value of this variable, we will get the same behavior as if it were not an inout parameter. However, we can also change where the inner reference is referring to by declaring it as an inout parameter:

We start by creating a second reference: person2 to the same instance as the person variable that currently has the name "Jamison" from before. After this, we pass the original person variable into our updatePerson: method and have this:

Behavior on input

In this method, we first change the name of the existing person to a new name. We can see in the output that the name of person2 has also changed, because both insidePerson inside the function and person2 are still referencing the same instance:

Behavior on input

However, we then also assign insidePerson to a completely new instance of the Person reference type. This results in person and person2 outside of the function pointing at two completely different instances of Person leaving the name of person2 to be "New Name" and updating the name of person to "New Person":

Behavior on input

Here, by defining insidePerson as an inout parameter, we were able to change where the passed-in variable was referencing. It can help us to visualize all the different types as one type pointing to another.

At any point, any of these arrows can be pointed at something new using an assignment and the instance can always be accessed through the references.

The last behavior we have to worry about is when variables are captured within closures. This is what we did not cover about closures in Chapter 5, A Modern Paradigm – Closures and Functional Programming. Closures can actually use the variables that were defined in the same scope as the closure itself:

var nameToPrint = "Kai"
var printName = {
    print(nameToPrint)
}
printName() // "Kai"

This is very different from normal parameters that we have seen before. We actually do not specify nameToPrint as a parameter, nor do we pass it in when calling the method. Instead, the closure captures the nameToPrint variable that is defined before it. These types of captures act similarly to inout parameters in functions.

When a value type is captured, it can be changed and it will change the original value as well:

var outsideName = "Kai"
var setName = {
    outsideName = "New Name"
}
print(outsideName) // "Kai"
setName()
print(outsideName) // "New Name"

As you can see, outsideName was changed after the closure was called. This is exactly like an inout parameter.

When a reference type is captured, any changes will also be applied to the outside version of the variable:

var outsidePerson = Person(name: "Kai")
var setPersonName = {
    outsidePerson.name = "New Name"
}
print(outsidePerson.name) // "Kai"
setPersonName()
print(outsidePerson.name) // "New Name"

This is also exactly like an inout parameter.

The other part of closure capture that we need to keep in mind is that changing the captured value after the closure is defined will still affect the value within the closure. We can take advantage of this to use the printName closure we defined in the preceding section to print any name:

nameToPrint = "Kai"
printName() // Kai
nameToPrint = "New Name"
printName() // "New Name"

As you can see, we can change what printName prints out by changing the value of nameToPrint. This behavior is actually very hard to track down when it happens accidently, so it is usually a good idea to avoid capturing variables in closures whenever possible. In this case, we are taking advantage of the behavior, but more often than not, it will cause bugs. Here, it would be better to pass what we want to print as an argument.

Another way to avoid this behavior is to use a feature called capture lists. With this, you can specify the variables that you want to capture by copying them:

A capture list is defined at the beginning of a closure before any parameter. It is a comma-separated list of all the variables being captured, which we want to copy within square brackets. In this case, we requested nameToPrint to be copied, so when we change it later, it does not affect the value that is printed out. We will see more advanced uses of capture lists later in this chapter.

Behavior on input

Another

place where the behavior of a value type differs from a reference type is when passing them into functions and methods. However, the behavior is very simple to remember if you look at passing a variable or constant into a function as just another assignment. This means that when you pass a value type into a function, it is copied while a reference type still shares the same instance:

Here we have defined a function that takes both a reference type: Person and a value type: String. When we update the Person type within the function, the person we passed in is also changed:

However, when we change the string within the function, the String passed into it remains unchanged.

The place where things get a little more complicated is with inout parameters. An inout parameter is actually a reference to the passed-in instance. This means that, it will treat a value type as if it were a reference type:

As you can see, when we changed the inout version of string within the function, it also changed the someString variable outside of the function just as if it were a reference type.

If we remember that a reference type is just a special version of a value type where the value is a reference, we can infer what will be possible with an inout version of a reference type. When we define an inout reference type, we actually have a reference to a reference; this reference is then the one that is pointing to a reference. We can visualize the difference between an inout value type and an inout reference type as shown:

Behavior on input

If we simply change the value of this variable, we will get the same behavior as if it were not an inout parameter. However, we can also change where the inner reference is referring to by declaring it as an inout parameter:

We start by creating a second reference: person2 to the same instance as the person variable that currently has the name "Jamison" from before. After this, we pass the original person variable into our updatePerson: method and have this:

Behavior on input

In this method, we first change the name of the existing person to a new name. We can see in the output that the name of person2 has also changed, because both insidePerson inside the function and person2 are still referencing the same instance:

Behavior on input

However, we then also assign insidePerson to a completely new instance of the Person reference type. This results in person and person2 outside of the function pointing at two completely different instances of Person leaving the name of person2 to be "New Name" and updating the name of person to "New Person":

Behavior on input

Here, by defining insidePerson as an inout parameter, we were able to change where the passed-in variable was referencing. It can help us to visualize all the different types as one type pointing to another.

At any point, any of these arrows can be pointed at something new using an assignment and the instance can always be accessed through the references.

The last behavior we have to worry about is when variables are captured within closures. This is what we did not cover about closures in Chapter 5, A Modern Paradigm – Closures and Functional Programming. Closures can actually use the variables that were defined in the same scope as the closure itself:

var nameToPrint = "Kai"
var printName = {
    print(nameToPrint)
}
printName() // "Kai"

This is very different from normal parameters that we have seen before. We actually do not specify nameToPrint as a parameter, nor do we pass it in when calling the method. Instead, the closure captures the nameToPrint variable that is defined before it. These types of captures act similarly to inout parameters in functions.

When a value type is captured, it can be changed and it will change the original value as well:

var outsideName = "Kai"
var setName = {
    outsideName = "New Name"
}
print(outsideName) // "Kai"
setName()
print(outsideName) // "New Name"

As you can see, outsideName was changed after the closure was called. This is exactly like an inout parameter.

When a reference type is captured, any changes will also be applied to the outside version of the variable:

var outsidePerson = Person(name: "Kai")
var setPersonName = {
    outsidePerson.name = "New Name"
}
print(outsidePerson.name) // "Kai"
setPersonName()
print(outsidePerson.name) // "New Name"

This is also exactly like an inout parameter.

The other part of closure capture that we need to keep in mind is that changing the captured value after the closure is defined will still affect the value within the closure. We can take advantage of this to use the printName closure we defined in the preceding section to print any name:

nameToPrint = "Kai"
printName() // Kai
nameToPrint = "New Name"
printName() // "New Name"

As you can see, we can change what printName prints out by changing the value of nameToPrint. This behavior is actually very hard to track down when it happens accidently, so it is usually a good idea to avoid capturing variables in closures whenever possible. In this case, we are taking advantage of the behavior, but more often than not, it will cause bugs. Here, it would be better to pass what we want to print as an argument.

Another way to avoid this behavior is to use a feature called capture lists. With this, you can specify the variables that you want to capture by copying them:

A capture list is defined at the beginning of a closure before any parameter. It is a comma-separated list of all the variables being captured, which we want to copy within square brackets. In this case, we requested nameToPrint to be copied, so when we change it later, it does not affect the value that is printed out. We will see more advanced uses of capture lists later in this chapter.

Closure capture behavior

The

last behavior we have to worry about is when variables are captured within closures. This is what we did not cover about closures in Chapter 5, A Modern Paradigm – Closures and Functional Programming. Closures can actually use the variables that were defined in the same scope as the closure itself:

var nameToPrint = "Kai"
var printName = {
    print(nameToPrint)
}
printName() // "Kai"

This is very different from normal parameters that we have seen before. We actually do not specify nameToPrint as a parameter, nor do we pass it in when calling the method. Instead, the closure captures the nameToPrint variable that is defined before it. These types of captures act similarly to inout parameters in functions.

When a value type is captured, it can be changed and it will change the original value as well:

var outsideName = "Kai"
var setName = {
    outsideName = "New Name"
}
print(outsideName) // "Kai"
setName()
print(outsideName) // "New Name"

As you can see, outsideName was changed after the closure was called. This is exactly like an inout parameter.

When a reference type is captured, any changes will also be applied to the outside version of the variable:

var outsidePerson = Person(name: "Kai")
var setPersonName = {
    outsidePerson.name = "New Name"
}
print(outsidePerson.name) // "Kai"
setPersonName()
print(outsidePerson.name) // "New Name"

This is also exactly like an inout parameter.

The other part of closure capture that we need to keep in mind is that changing the captured value after the closure is defined will still affect the value within the closure. We can take advantage of this to use the printName closure we defined in the preceding section to print any name:

nameToPrint = "Kai"
printName() // Kai
nameToPrint = "New Name"
printName() // "New Name"

As you can see, we can change what printName prints out by changing the value of nameToPrint. This behavior is actually very hard to track down when it happens accidently, so it is usually a good idea to avoid capturing variables in closures whenever possible. In this case, we are taking advantage of the behavior, but more often than not, it will cause bugs. Here, it would be better to pass what we want to print as an argument.

Another way to avoid this behavior is to use a feature called capture lists. With this, you can specify the variables that you want to capture by copying them:

A capture list is defined at the beginning of a closure before any parameter. It is a comma-separated list of all the variables being captured, which we want to copy within square brackets. In this case, we requested nameToPrint to be copied, so when we change it later, it does not affect the value that is printed out. We will see more advanced uses of capture lists later in this chapter.

Now that we understand the different ways in which data is represented in Swift, we can look into how we can manage the memory better. Every instance that we create takes up memory. Naturally, it wouldn't make sense to keep all data around forever. Swift needs to be able to free up memory so that it can be used for other purposes, once our program doesn't need it anymore. This is the key to managing memory in our apps. We need to make sure that Swift can free up all the memory that we no longer need, as soon as possible.

The way that Swift knows it can free up memory is when the code can no longer access an instance. If there is no longer any variable or constant referencing an instance, it can be repurposed for another instance. This is called "freeing the memory" or "deleting the object".

In Chapter 3, One Piece at a Time – Types, Scopes, and Projects we already discussed when a variable is accessible or not in the section about scopes. This makes memory management very simple for value types. Since value types are always copied when they are reassigned or passed into functions, they can be immediately deleted once they go out of scope. We can look at a simple example to get the full picture:

func printSomething() {
    let something = "Hello World!"
    print(something)
}

Here we have a very simple function that prints out "Hello World!". When printSomething is called, something is assigned to a new instance of String with the value "Hello World!". After print is called, the function exits and therefore something is no longer in scope. At that point, the memory being taken up by something can be freed.

While this is very simple, reference types are much more complex. At a high level, an instance of a reference type is deleted at the point that there is no longer any reference to the instance in scope anymore. This is relatively straightforward to understand but it gets more complex in the details. The Swift feature that manages this is called Automatic Reference Counting or ARC for short.

The key to ARC is that every object has relationships with one or more variables. This can be extended to include the idea that all objects have a relationship with other objects. For example, a car object would contain objects for its four tires, engine, and so on. It will also have a relationship with its manufacturer, dealership, and owner. ARC uses these relationships to determine when an object can be deleted. In Swift, there are three different types of relationships: strong, weak, and unowned.

The first, and default type of relationship is a strong relationship. It says that a variable requires the instance it is referring to always exist, as long as the variable is still in scope. This is the only behavior available for value types. When an instance no longer has any strong relationships to it, it will be deleted.

A great example of this type of relationship is with a car that must have a steering wheel:

By default, the steeringWheel property has a strong relationship to the SteeringWheel instance it is initialized with. Conceptually, this means that the car itself has a strong relationship to the steering wheel. As long as a car exists, it must have a relationship to a steering wheel that exists. Since steeringWheel is declared as a variable, we could change the steering wheel of the car, which would remove the old strong relationship and add a new one, but a strong relationship will always exist.

If we were to create a new instance of Car and store it in a variable, that variable would have a strong relationship to the car:

Lets break down all the relationships in this code. First we create the wheel constant and assign it to a new instance of SteeringWheel. This sets up a strong relationship from wheel to the new instance. We do the same thing with the car constant, but this time we also pass in the wheel constant to the initializer. Now, not only does car have a strong relationship to the new Car instance, but the Car initializer also creates a strong relationship from the steeringWheel property to the same instance as the wheel constant:

Strong

So what does this relationship graph mean for memory management? At this time, the Car instance has one strong relationship: the car constant, and the SteeringWheel instance has two strong relationships: the wheel constant and the steeringWheel property of the Car instance.

This means that the Car instance will be deleted as soon as the car constant goes out of scope. On the other hand, the SteeringWheel instance will only be deleted after both the wheel constant goes out of scope and the Car instance is deleted.

You can envision a strong reference counter on every instance in your program. Every time a strong relationship is setup to an instance the counter goes up. Every time an object strongly referencing it gets deleted, the counter goes down. If that counter ever goes back to zero, the instance is deleted.

The other important thing to realize is that all relationships are only in one direction. Just because the Car instance has a strong relationship to the SteeringWheel instance does not mean that the SteeringWheel instance has any relationship back. You could add your own relationship back by adding a car property to the SteeringWheel class, but you have to be careful when doing this, as we will see in the strong reference cycle section coming up.

Object relationships

The key

to ARC is that every object has relationships with one or more variables. This can be extended to include the idea that all objects have a relationship with other objects. For example, a car object would contain objects for its four tires, engine, and so on. It will also have a relationship with its manufacturer, dealership, and owner. ARC uses these relationships to determine when an object can be deleted. In Swift, there are three different types of relationships: strong, weak, and unowned.

The first, and default type of relationship is a strong relationship. It says that a variable requires the instance it is referring to always exist, as long as the variable is still in scope. This is the only behavior available for value types. When an instance no longer has any strong relationships to it, it will be deleted.

A great example of this type of relationship is with a car that must have a steering wheel:

By default, the steeringWheel property has a strong relationship to the SteeringWheel instance it is initialized with. Conceptually, this means that the car itself has a strong relationship to the steering wheel. As long as a car exists, it must have a relationship to a steering wheel that exists. Since steeringWheel is declared as a variable, we could change the steering wheel of the car, which would remove the old strong relationship and add a new one, but a strong relationship will always exist.

If we were to create a new instance of Car and store it in a variable, that variable would have a strong relationship to the car:

Lets break down all the relationships in this code. First we create the wheel constant and assign it to a new instance of SteeringWheel. This sets up a strong relationship from wheel to the new instance. We do the same thing with the car constant, but this time we also pass in the wheel constant to the initializer. Now, not only does car have a strong relationship to the new Car instance, but the Car initializer also creates a strong relationship from the steeringWheel property to the same instance as the wheel constant:

Strong

So what does this relationship graph mean for memory management? At this time, the Car instance has one strong relationship: the car constant, and the SteeringWheel instance has two strong relationships: the wheel constant and the steeringWheel property of the Car instance.

This means that the Car instance will be deleted as soon as the car constant goes out of scope. On the other hand, the SteeringWheel instance will only be deleted after both the wheel constant goes out of scope and the Car instance is deleted.

You can envision a strong reference counter on every instance in your program. Every time a strong relationship is setup to an instance the counter goes up. Every time an object strongly referencing it gets deleted, the counter goes down. If that counter ever goes back to zero, the instance is deleted.

The other important thing to realize is that all relationships are only in one direction. Just because the Car instance has a strong relationship to the SteeringWheel instance does not mean that the SteeringWheel instance has any relationship back. You could add your own relationship back by adding a car property to the SteeringWheel class, but you have to be careful when doing this, as we will see in the strong reference cycle section coming up.

Strong

The first, and

default type of relationship is a strong relationship. It says that a variable requires the instance it is referring to always exist, as long as the variable is still in scope. This is the only behavior available for value types. When an instance no longer has any strong relationships to it, it will be deleted.

A great example of this type of relationship is with a car that must have a steering wheel:

By default, the steeringWheel property has a strong relationship to the SteeringWheel instance it is initialized with. Conceptually, this means that the car itself has a strong relationship to the steering wheel. As long as a car exists, it must have a relationship to a steering wheel that exists. Since steeringWheel is declared as a variable, we could change the steering wheel of the car, which would remove the old strong relationship and add a new one, but a strong relationship will always exist.

If we were to create a new instance of Car and store it in a variable, that variable would have a strong relationship to the car:

Lets break down all the relationships in this code. First we create the wheel constant and assign it to a new instance of SteeringWheel. This sets up a strong relationship from wheel to the new instance. We do the same thing with the car constant, but this time we also pass in the wheel constant to the initializer. Now, not only does car have a strong relationship to the new Car instance, but the Car initializer also creates a strong relationship from the steeringWheel property to the same instance as the wheel constant:

Strong

So what does this relationship graph mean for memory management? At this time, the Car instance has one strong relationship: the car constant, and the SteeringWheel instance has two strong relationships: the wheel constant and the steeringWheel property of the Car instance.

This means that the Car instance will be deleted as soon as the car constant goes out of scope. On the other hand, the SteeringWheel instance will only be deleted after both the wheel constant goes out of scope and the Car instance is deleted.

You can envision a strong reference counter on every instance in your program. Every time a strong relationship is setup to an instance the counter goes up. Every time an object strongly referencing it gets deleted, the counter goes down. If that counter ever goes back to zero, the instance is deleted.

The other important thing to realize is that all relationships are only in one direction. Just because the Car instance has a strong relationship to the SteeringWheel instance does not mean that the SteeringWheel instance has any relationship back. You could add your own relationship back by adding a car property to the SteeringWheel class, but you have to be careful when doing this, as we will see in the strong reference cycle section coming up.

Weak

The
Unowned

The final

A strong reference cycle is when two instances directly or indirectly hold strong references to each other. This means that neither object can ever be deleted, because both are ensuring that the other will always exist.

This scenario is our first really bad memory management scenario. It is one thing to keep memory around longer than it is needed; it is a whole different level to create memory that can never be freed up to be reused again. This type of memory problem is called a memory leak, because the computer will slowly leak memory until there is no longer any new memory available. This is why you will sometimes see a speed improvement after restarting your device. Upon restart, all of the memory is freed up again. Modern operating systems will sometimes find ways to forcefully free up memory, especially when completely quitting an app, but we cannot rely on this as programmers.

So how can we prevent these strong reference cycles? First, let's take a look at what they look like. There are two main scenarios where these cycles can exist: between objects and with closures.

A strong reference cycle between objects is when two types directly or indirectly contain strong references to each other.

A great example of a strong reference cycle between objects is if we rewrite our preceding car example without using a weak reference from SteeringWheel to Car:

The only difference between this code and the preceding code is that the car property on SteeringWheel is no longer declared as weak. This means that when a car is created, it will set up a strong relationship to the SteeringWheel instance and then create a strong reference from the SteeringWheel instance back to the car:

Spotting

This scenario means that the reference count of both instances can never go down to zero and therefore they will never be deleted and the memory will be leaked.

Two objects can also indirectly hold strong references to each other through one or more third parties:

Here, we have the scenario where a Car can have a strong reference to a SteeringWheel that can have a strong reference to a Manufacturer that in turn has a strong reference to the original Car:

Spotting

This is another strong reference cycle and it illustrates two more important points. First, optionals, by default, still create strong relationships when not nil. Also, the built in container types, such as arrays and dictionaries, also create strong relationships.

Clearly strong reference cycles can be difficult to spot, especially because they are hard to detect in the first place. An individual memory leak is rarely going to be noticeable to a user of your program, but if you continuously leak memory over and over again, it can cause their device to feel sluggish or even crash.

The best way as a developer to detect them is to use a tool built into Xcode called Instruments. Instruments can do many things, but one of those things is called Leaks. To run this tool you must have an Xcode Project; you cannot run it on a Playground. It is run by selecting Product | Profile from the menu bar.

This will build your project and display a series of profiling tools:

Spotting

If you select the Leaks tool and press the record button in the upper-left corner, it will run your program and warn you of memory leaks which it can detect. A memory leak will look like a red X icon and will be listed as a leaked object:

Spotting

You can even select the Cycles & Roots view for the leaked objects and Instruments will show you a visual representation of your strong reference cycle. In the following screenshot, you can see that there is a cycle between SteeringWheel and Car:

Spotting

Clearly, Leaks is a powerful tool and you should run it periodically on your code, but it will not catch all strong reference cycles. The last line of defense is going to be you staying vigilant with your code, always thinking about the ownership graph.

Of course, spotting cycles is only part of the battle. The other part of the battle is fixing them.

The easiest way to break a strong reference cycle is to simply remove one of the relationships completely. However, this is very often not going to be an option. A lot of the time, it is important to have a two-way relationship.

The way we fix cycles without completely removing a relationship is to make one or more of the relationships weak or unowned. In fact, this is the main reason that these other two types of relationships exist.

We fix the strong reference cycle in our original example by changing the car relationship back to weak:

Now Car has a strong reference to SteeringWheel but there is only a weak reference back:

Fixing

How you break any given cycle is going to depend on your implementation. The only important part is that somewhere in the cycle of references there is a weak or unowned relationship.

Unowned relationships are good for scenarios where the connection will never be missing. In our example, there are times that a SteeringWheel exists without a car reference. If we change it so that the SteeringWheel is created in the Car initializer, we could make the reference unowned:

Also, note that we had to define the steeringWheel property as an implicitly unwrapped optional. This is because we had to use self when initializing it but at the same time we cannot use self until all the properties have a value. Making it optional allows it to be nil while we are using self to create the steering wheel. This is safe as long as the SteeringWheel2 initializer doesn't try to access the steeringWheel property of the passed in car.

As we found out in Chapter 5, A Modern Paradigm – Closures and Functional Programming, closures are just another type of object, so they follow the same ARC rules. However, they are subtler than classes because of their ability to capture variables from their surrounding scope. These captures create strong references from the closures to the captured variable that are often overlooked because capturing variables looks so natural compared to conditionals, for loops and other similar syntax.

Just as classes can create circular references, so can closures. Something can have a strong reference to a closure that directly or indirectly has a strong reference back to the original object. Let's take a look at how we can spot that.

Between objects

A

strong reference cycle between objects is when two types directly or indirectly contain strong references to each other.

A great example of a strong reference cycle between objects is if we rewrite our preceding car example without using a weak reference from SteeringWheel to Car:

The only difference between this code and the preceding code is that the car property on SteeringWheel is no longer declared as weak. This means that when a car is created, it will set up a strong relationship to the SteeringWheel instance and then create a strong reference from the SteeringWheel instance back to the car:

Spotting

This scenario means that the reference count of both instances can never go down to zero and therefore they will never be deleted and the memory will be leaked.

Two objects can also indirectly hold strong references to each other through one or more third parties:

Here, we have the scenario where a Car can have a strong reference to a SteeringWheel that can have a strong reference to a Manufacturer that in turn has a strong reference to the original Car:

Spotting

This is another strong reference cycle and it illustrates two more important points. First, optionals, by default, still create strong relationships when not nil. Also, the built in container types, such as arrays and dictionaries, also create strong relationships.

Clearly strong reference cycles can be difficult to spot, especially because they are hard to detect in the first place. An individual memory leak is rarely going to be noticeable to a user of your program, but if you continuously leak memory over and over again, it can cause their device to feel sluggish or even crash.

The best way as a developer to detect them is to use a tool built into Xcode called Instruments. Instruments can do many things, but one of those things is called Leaks. To run this tool you must have an Xcode Project; you cannot run it on a Playground. It is run by selecting Product | Profile from the menu bar.

This will build your project and display a series of profiling tools:

Spotting

If you select the Leaks tool and press the record button in the upper-left corner, it will run your program and warn you of memory leaks which it can detect. A memory leak will look like a red X icon and will be listed as a leaked object:

Spotting

You can even select the Cycles & Roots view for the leaked objects and Instruments will show you a visual representation of your strong reference cycle. In the following screenshot, you can see that there is a cycle between SteeringWheel and Car:

Spotting

Clearly, Leaks is a powerful tool and you should run it periodically on your code, but it will not catch all strong reference cycles. The last line of defense is going to be you staying vigilant with your code, always thinking about the ownership graph.

Of course, spotting cycles is only part of the battle. The other part of the battle is fixing them.

The easiest way to break a strong reference cycle is to simply remove one of the relationships completely. However, this is very often not going to be an option. A lot of the time, it is important to have a two-way relationship.

The way we fix cycles without completely removing a relationship is to make one or more of the relationships weak or unowned. In fact, this is the main reason that these other two types of relationships exist.

We fix the strong reference cycle in our original example by changing the car relationship back to weak:

Now Car has a strong reference to SteeringWheel but there is only a weak reference back:

Fixing

How you break any given cycle is going to depend on your implementation. The only important part is that somewhere in the cycle of references there is a weak or unowned relationship.

Unowned relationships are good for scenarios where the connection will never be missing. In our example, there are times that a SteeringWheel exists without a car reference. If we change it so that the SteeringWheel is created in the Car initializer, we could make the reference unowned:

Also, note that we had to define the steeringWheel property as an implicitly unwrapped optional. This is because we had to use self when initializing it but at the same time we cannot use self until all the properties have a value. Making it optional allows it to be nil while we are using self to create the steering wheel. This is safe as long as the SteeringWheel2 initializer doesn't try to access the steeringWheel property of the passed in car.

As we found out in Chapter 5, A Modern Paradigm – Closures and Functional Programming