Before you begin
This section tells you a few things you need to know before you begin, such as what hardware and software you need, where to find the project files for this book, and more.
Section I: Swift Basics
The chapters in this section will introduce you to the basics of programming in Swift. From the basics of how computers work up to language structures, you will cover enough of the language to be able to work with data and organize code behavior.
The section begins with some groundwork to get you started. Once you have the basic data types in mind, it’s time to do things with this data, and finally you will learn about an important data type, optional, that allows you to express potentially missing data.
These basics will get you started quickly, and before you know it, you will be ready for the more advanced topics that follow. Let̵
This is it, your whirlwind introduction to the programming world! You start with an overview of computers and programming, and then greet you at Swift playgrounds, where you will spend your coding time for the rest of this book. You learn some basic things like code comments, arithmetic operations, constants and variables. These are some of the basic building blocks of any language, and Swift is no different.
You learn about handling different types, including strings that allow you to represent text. You will learn about conversion between types, and you will also get an introduction to the type of inference, which makes your life as a programmer much easier. You learn about tuple types that allow you to group values of any type together.
You learn how to make decisions and repeat tasks in your programs using the syntax to control the flow. You will also learn about boilers, which represent true and false values, and how you can use them to compare data.
Continuing the theme of the code not running in a straight line, you will learn about another loop known as the `for` loop. You also learn about switch statements that are particularly powerful in Swift.
Features are the basic building blocks you use to structure your Swift code. You’ll learn how to define features to group your code into reusable devices.
This chapter covers accessories, a special type in Swift that represent either a real value or the absence of a value. Towards the end of this chapter, you will know why you need accessories and how to use them safely.
Section II: Collection Types
So far, you have mostly seen data in the form of individual elements. Although the tuples may have more data, you must specify the size in advance. a tuple with three strings is a completely different type than a tuple with two strings, and converting between them is not trivial. In this section you will learn about collection types in Swift. The collections are flexible “containers” that allow you to store any number of values together.
There are several collection types in Swift, but three important ones are matrices, dictionaries and sets. You learn to use custom operations and loops over collection types. Finally, you will return to strings, which are collections of characters.
All collection types have similar interfaces, but have very different uses. As you read through these chapters, keep in mind the differences, and you will begin to develop a sense of what type to use when.
As part of exploring the differences between collection types, you will also want to consider performance: how quickly collections can perform specific operations, such as adding to the collection or searching through it.
The usual way to talk about performance is with large-O notation. If you are not already familiar with it, read on for a brief introduction.
We present big-O notation
Big-O notation is a way of describing operating time, or how long an operation takes to complete. The idea is that the exact time an operation takes is not important; it is the relative difference in scale that matters.
Imagine that you have a list of names in a random order, and you need to look up the first name of the list. It does not matter if the list has a single name or a million names – looking at the very first name always takes the same amount of time. It is an example of one constant time operation, or O (1) in large-O notation.
Now say you need to find a specific name on the list. You need to scan through the list and look at each name until you either find a match or reach the end. Again, we are not concerned with the exact time this takes, only the relative time compared to other operations.
To find out the driving time, think in terms of work units. You have to look at each name, so be aware that there is one “work unit” per name. If you had 100 names, there are 100 units. What if you double the number of names to 200? How does it change the workload? The answer is yes also doubles the workload. Similarly, quadrupling the number of names quadruples the amount of work.
This increase in work is an example of one linear time operation, or O(N) in large-O notation. The input size is the variable N, which means that the time the process takes is also N. There is a direct, linear relationship between the input size (number of names in the list) and the time it takes to search for a Name.
You can see why constant time operations use number one in O(1). They are just a single work unit, anyway!
You can read more about big-O notation by searching online. You only need constant time and linear time in this book, but there are others like it time complexities out there.
Big-O notation is especially important when working with collection types because collections can store large amounts of data. You must be aware of runtime when adding, deleting or editing values.
For example, if collection type A has a constant time search and collection type B has a linear time search, what you choose to use will depend on how many searches you plan to do.
Arrays are the most common type of collection you will encounter in Swift. Arrays are written, like regular variables and constants, and store multiple values as a single list.
Swift has an object you can use to divide the code into reusable pieces: a closure. These are especially important when working with collections.
Finally, you will look at the strings that are two-way collections of Unicode characters.
Section III: Build your own types
You can create your own type by combining variables and functions into a new type definition. For example, integers and doubles may not be enough for your purposes, so you may need to create a type to store complex numbers. Or it may be difficult to manage first, middle, and last names in three independent variables, so you decide to create a FullName type.
When you create a new type, you give it a name; thus, these custom types are known as named types. Structures are a powerful tool for modeling real concepts. You can encapsulate related concepts, properties and methods into a single, coherent model.
Swift includes four types of named types: structures, classes, enumerations, and protocols. Now that you understand how structures work with methods and properties, you can see how the other named types use the same concepts, how they are different, and where you want to use each.
Finally, you expand your knowledge of the type system by learning about generics: types and methods that take as input other types instead of just methods. Swift’s key to safety, speed and expressiveness lies in the ability to use generic types.
Custom types make it possible to build large and complex things with the basic building blocks you have learned so far. It’s time to take the Swift apprentice to the next level!
This chapter introduces the former type structures. Structures are types that can store named properties and define actions and behaviors.
In this chapter you will learn about stored and calculated properties, along with some tricks, such as how to monitor changes in a property’s value and delay the initialization of a stored property.
Methods are just functions that lie in a structure. You will take a closer look at how methods and initializers help you build more complex structures.
Structures introduced you to the former type, allowing you to define your own named types. In this chapter you will get acquainted with classes, which are similar to structures.
This chapter introduces the finer points of classes and helps you understand how to create, use, and manage complex classes.
In this chapter you will learn about enumerations, a type that groups related values. You will also finally discover what an optional is under the hood.
Protocols are a type that can bridge common behaviors between structures, classes, and enums by defining an interface or template for an actual concrete type.
In this chapter you will learn what generics are, learn how to write your own generic code, and go back and look at generic types in Swift – dictionaries, matrices and optional – from this new perspective.
Section IV: Advanced Topics
You have come to the last part of this book! In this section, you will delve into some important but more advanced topics to round off the Swift apprentice.
Swift gives you powerful tools to hide complexity and organize your code into easier-to-digest devices. This chapter describes how to do this.
You learn how to define your own operators and subscriptions so that your types feel even more like built-in language constructions.
With pattern matching, you can achieve more – with less writing. You will master all its many forms in this chapter.
In the real world, you can avoid mistakes. Graceful handling of errors is what separates mediocre code from good code.
You will learn about the type of serialization system introduced in Swift 4 with particular emphasis on the JSON format.
This chapter delves into the details of Swift memory management that examines the relationship between objects. It shows you how to avoid common leaks.
Value semantics has a clear advantage over reference semantics when it comes to local reasoning, but can lead to inefficiency for large objects. This chapter shows you how to get the best of both worlds.
From the standard library to user-generated generics, Swift is a protocol-based language. In this chapter you will see how to get all the benefits associated with object-oriented programming while being able to avoid most of the difficulties.
Learn how to use restrictions to make generic code more useful and how to hide implementation details with opaque return types.