Book Image

Swift: Developing iOS Applications

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

Swift: Developing iOS Applications

By: Jon Hoffman, Andrew J Wagner, Giordano Scalzo

Overview of this book

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

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.