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

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

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

In this chapter, we will cover the following topics:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Generic function

In

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Generic type

Similar to a

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Type constraints

Before

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

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

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

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

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

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

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

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

Protocol constraints

Let's say that we

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

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

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

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

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

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

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

Where clauses for protocols

You can
Where clauses for equality

If we want to write a

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

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

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

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

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

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

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

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

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

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

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

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

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

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

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

class Building {
    // ...

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

class House: Building {
    // ...

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

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

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

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

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

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

Adding methods to all forms of a generic

Knowing that

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

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

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

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

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

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

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

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

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

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

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

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

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

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

class Building {
    // ...

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

class House: Building {
    // ...

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

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

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

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

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

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

Adding methods to only certain instances of a generic

A

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

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

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

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

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

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

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

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

class Building {
    // ...

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

class House: Building {
    // ...

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

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

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

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

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

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

Extending protocols

We first discussed

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

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

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

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

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

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

protocol Building {
    var squareFootage: Int {get}
}

struct House: Building {
    let squareFootage: Int
}

struct Factory: Building {
    let squareFootage: Int
}

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

class Building {
    // ...

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

class House: Building {
    // ...

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

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

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

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

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

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

One cool part of Swift is generators and sequences. They provide an easy way to iterate over a list of values. Ultimately, they boil down to two different protocols: GeneratorType and SequenceType. If you implement the SequenceType protocol in your custom types, it allows you to use the for-in loop over an instance of your type. In this section, we will look at how we can do that.

The most critical part of this is the GeneratorType protocol. Essentially, a generator is an object that you can repeatedly ask for the next object in a series until there are no objects left. Most of the time you can simply use an array for this, but it is not always the best solution. For example, you can even make a generator that is infinite.

There is a famous infinite series of numbers called the Fibonacci sequence, where every number in the series is the sum of the two previous numbers. This is especially famous because it is found all over nature from the number of bees in a nest to the most pleasing aspect ratio of a rectangle to look at. Let's create an infinite generator that will produce this series.

We start by creating a structure that implements the GeneratorType protocol. The protocol is made up of two pieces. First, it has a type alias for the type of elements in the sequence and second, it has a mutating method called next that returns the next object in the sequence.

The implementation looks similar to this:

We defined a property called values that is a tuple representing the previous two values in the sequence. We update values and return the first element of the tuple each time next is called. This means that there will be no end to the sequence.

We can use this generator on its own by instantiating it and then repeatedly calling next inside a while loop:

We need to set up some sort of a condition so that the loop doesn't go on forever. In this case, we break out of the loop once the numbers get above 10. However, this code is pretty ugly, so Swift also defines the protocol called SequenceType to clean it up.

SequenceType is another protocol that is defined as having a type alias for a GeneratorType and a method called generate that returns a new generator of that type. We could declare a simple sequence for our FibonacciGenerator, as follows:

Every for-in loop operates on the SequenceType protocol, so now we can use a for-in loop on our FibonacciSequence:

This is pretty cool; we can easily iterate over the Fibonacci sequence in a very readable way. It is much easier to understand the preceding code than it would be to understand a complicated while loop that has to calculate the next value of the sequence each time. Imagine all of the other type of sequences we can design such as prime numbers, random name generators, and so on.

However, it is not always ideal to have to define two different types to create a single sequence. To fix this, we can use generics. Swift provides a generic type called AnyGenerator with a companion function called anyGenerator:. This function takes a closure and returns a generator that uses the closure as its next method. This means that we don't have to explicitly create a generator ourselves; instead we can use anyGenerator: directly in a sequence:

In this version of FibonacciSequence, we create a new generator every time generate is called that takes a closure that does the same thing that our original FibonacciGenerator was doing. We declare the values variable outside of the closure so that we can use it to store the state between calls to the closure. If your generator is simple and doesn't require a complicated state, using the AnyGenerator generic is a great way to go.

Now let's use this FibonacciSequence to solve the kind of math problem that computers are great at.

What if we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.

Generators

The most

critical part of this is the GeneratorType protocol. Essentially, a generator is an object that you can repeatedly ask for the next object in a series until there are no objects left. Most of the time you can simply use an array for this, but it is not always the best solution. For example, you can even make a generator that is infinite.

There is a famous infinite series of numbers called the Fibonacci sequence, where every number in the series is the sum of the two previous numbers. This is especially famous because it is found all over nature from the number of bees in a nest to the most pleasing aspect ratio of a rectangle to look at. Let's create an infinite generator that will produce this series.

We start by creating a structure that implements the GeneratorType protocol. The protocol is made up of two pieces. First, it has a type alias for the type of elements in the sequence and second, it has a mutating method called next that returns the next object in the sequence.

The implementation looks similar to this:

We defined a property called values that is a tuple representing the previous two values in the sequence. We update values and return the first element of the tuple each time next is called. This means that there will be no end to the sequence.

We can use this generator on its own by instantiating it and then repeatedly calling next inside a while loop:

We need to set up some sort of a condition so that the loop doesn't go on forever. In this case, we break out of the loop once the numbers get above 10. However, this code is pretty ugly, so Swift also defines the protocol called SequenceType to clean it up.

SequenceType is another protocol that is defined as having a type alias for a GeneratorType and a method called generate that returns a new generator of that type. We could declare a simple sequence for our FibonacciGenerator, as follows:

Every for-in loop operates on the SequenceType protocol, so now we can use a for-in loop on our FibonacciSequence:

This is pretty cool; we can easily iterate over the Fibonacci sequence in a very readable way. It is much easier to understand the preceding code than it would be to understand a complicated while loop that has to calculate the next value of the sequence each time. Imagine all of the other type of sequences we can design such as prime numbers, random name generators, and so on.

However, it is not always ideal to have to define two different types to create a single sequence. To fix this, we can use generics. Swift provides a generic type called AnyGenerator with a companion function called anyGenerator:. This function takes a closure and returns a generator that uses the closure as its next method. This means that we don't have to explicitly create a generator ourselves; instead we can use anyGenerator: directly in a sequence:

In this version of FibonacciSequence, we create a new generator every time generate is called that takes a closure that does the same thing that our original FibonacciGenerator was doing. We declare the values variable outside of the closure so that we can use it to store the state between calls to the closure. If your generator is simple and doesn't require a complicated state, using the AnyGenerator generic is a great way to go.

Now let's use this FibonacciSequence to solve the kind of math problem that computers are great at.

What if we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.

Sequences

SequenceType is

another protocol that is defined as having a type alias for a GeneratorType and a method called generate that returns a new generator of that type. We could declare a simple sequence for our FibonacciGenerator, as follows:

Every for-in loop operates on the SequenceType protocol, so now we can use a for-in loop on our FibonacciSequence:

This is pretty cool; we can easily iterate over the Fibonacci sequence in a very readable way. It is much easier to understand the preceding code than it would be to understand a complicated while loop that has to calculate the next value of the sequence each time. Imagine all of the other type of sequences we can design such as prime numbers, random name generators, and so on.

However, it is not always ideal to have to define two different types to create a single sequence. To fix this, we can use generics. Swift provides a generic type called AnyGenerator with a companion function called anyGenerator:. This function takes a closure and returns a generator that uses the closure as its next method. This means that we don't have to explicitly create a generator ourselves; instead we can use anyGenerator: directly in a sequence:

In this version of FibonacciSequence, we create a new generator every time generate is called that takes a closure that does the same thing that our original FibonacciGenerator was doing. We declare the values variable outside of the closure so that we can use it to store the state between calls to the closure. If your generator is simple and doesn't require a complicated state, using the AnyGenerator generic is a great way to go.

Now let's use this FibonacciSequence to solve the kind of math problem that computers are great at.

What if we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.

Product of Fibonacci numbers under 50

What if

we want to know what is the result of multiplying every number in the Fibonacci sequence under 50? We can try to use a calculator and painstakingly enter in all of the numbers, but it is much more efficient to do it in Swift.

Let's start by creating a generic SequenceType that will take another sequence type and limit it to stop the sequence once it has reached a maximum number. We need to make sure that the type of the maximum value matches the type in the sequence and also that the element type is comparable. For that, we can use a where clause on the element type:

Notice that when we refer to the element type, we must go through the generator type.

When our SequenceLimiter structure is created, it stores the original sequence. This is so that it can use the result of its generate method each time generate is called on this parent sequence. Each call to generate needs to start the sequence over again. It then creates an AnyGenerator with a closure that calls next on the locally initialized generator of the original sequence. If the value returned by the original generator is greater than or equal to the maximum value, we return nil, indicating that the sequence is over.

We can even add an extension to SequenceType with a method that will create a limiter for us:

We use Self as a placeholder representing the specific type of the instance the method is being called on.

Now, we can easily limit our Fibonacci sequence to only values under 50:

The last part we need to solve our problem is the ability to find the product of a sequence. We can do this with another extension. In this case, we are only going to support sequences that contain Ints so that we can ensure that the elements can be multiplied:

This method takes advantage of the reduce function to start with the value one and multiply it by every value in the sequence. Now we can do our final calculation easily:

Almost instantaneously, our program will return the result 2,227,680. Now we can really understand why we call these devices computers.