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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Closures as variables

Let's take

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Closures as parameters

We can

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

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

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

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

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

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

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

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

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

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

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

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

Syntactic sugar

First, we

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Now we are getting fancy!

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

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

Filter

The first

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

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

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

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

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

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

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

Now we are getting fancy!

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

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

Reduce

Swift also

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

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

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

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

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

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

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

Now we are getting fancy!

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

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

Map

Map is a
Sort

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

There are more

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

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

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

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

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

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

This even applies to looping through a result:

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

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

We can start by defining the same input data:

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

So let's write the random genre function:

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

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

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

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

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

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

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

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