Book Image

Learn Swift by Building Applications

By : Emil Atanasov, Giordano Scalzo, Emil Atanasov
Book Image

Learn Swift by Building Applications

By: Emil Atanasov, Giordano Scalzo, Emil Atanasov

Overview of this book

Swift Language is now more powerful than ever; it has introduced new ways to solve old problems and has gone on to become one of the fastest growing popular languages. It is now a de-facto choice for iOS developers and it powers most of the newly released and popular apps. This practical guide will help you to begin your journey with Swift programming through learning how to build iOS apps. You will learn all about basic variables, if clauses, functions, loops, and other core concepts; then structures, classes, and inheritance will be discussed. Next, you’ll dive into developing a weather app that consumes data from the internet and presents information to the user. The final project is more complex, involving creating an Instagram like app that integrates different external libraries. The app also uses CocoaPods as its package dependency manager, to give you a cutting-edge tool to add to your skillset. By the end of the book, you will have learned how to model real-world apps in Swift.
Table of Contents (14 chapters)
5
Adding Interactivity to Your First App

Variables

What is a variable? This is a place in the memory where we can store some data and use it later in our program. A good example is if you want to take an action based on a user's input, then the input should be stored somewhere on the device (computer). Usually, this place is in the device's memory. To let our program know that we need such a place, we have to express that. A var statement is used.

In Swift, declaring a variable looks like this:

var text = "Hello world!"

This code creates a place in the memory, called text, where we store the text, Hello world!. Later, we can use it to carry out some meaningful actions.

An advantage of a variable is that it can be changed later to contain a different value. Here, we should be careful—Swift is pretty strict about types (this will be discussed later), and, thus, we can't mix different value types. There are strict rules that should be followed, and we will get familiar with these soon. So, in our case, we can do the following to change the text that is stored in our variable, named text:

text = "Hey, It's Swift!"

Now we know what a variable is and how to work with variables. Let's try to do some calculations using variables, with stored integer values:

var five = 5
var four = 4
var sum = four + five

In the preceding code, we have created three variables. The first two were initialized with literal expressions, or simply with exact values. In the code, we can use complex calculations, and the Swift compiler will handle this case easily as follows:

var five = 2 + 3

This is the same as the previous code snippet.

The last variable sum is initialized with the value of the expression four + five. To calculate this expression, the compiler uses the values stored in the previously declared variables (on the previous lines). The evaluation happens once the code is executed. What does this mean: The evaluation happens once the code is executed? In short, if four or five contain different values, then the sum variable will reflect this. The code is working with the names of the places in memory, but the actual result depends on the values stored there.

We could read the preceding code like this:

  • Create a place in the memory, which we will call five, and store the value 5 in it

  • Create a place in the memory, which we will call four, and store the value 4 in it

  • Create another place in the memory, called sum, and store the value of the expression of what's stored in four plus what's stored in five

Usually, we use variables to allocate places in memory, which we will modify in the following code. But we don't always want to change the value of a variable once it is set. Thus, to simplify it, there is a special word in Swift, let, which denotes a place in the memory that won't be changed in the future. Its value is set initially and it can't be changed. (This is slightly different when we are working with objects, but this will become clear later in the book.)

The following code defines a place in memory that won't be updated. If we try to update it, then the Swift compiler will inform us that it is not possible. The value on the left is a constant and we are trying to change it:

let helloWorld = "Hello World!"
helloWorld = "Hello, Swift World!" //the compiler is complaining

The exact error is: Cannot assign to value: 'helloWorld' is a 'let' constant, which means that we are trying to set a new value to a constant.

Let's see how we can update our previous code snippets, once we know that there are var and let keywords.

The first code with the text variable should be the same, because we change the value of the variable text. The second code, with the sum of two integers, could be rewritten as follows:

let five = 5 
let four = 4
let sum = four + five

A good practice is to keep using let whenever possible. The compiler gives us hints all the time. Of course, it's possible to keep something stored in a variable instead of a constant while developing, but if we want to squeeze out every single bit of performance, then we should stick to the best practice—replace all unmodified variables with constants.

Why do we gain performance when using let? The short answer is, the compiler knows that this place in the memory will be used only for reading from operations, and it cuts all the extra logic, which is needed to support modifications. The developers can reason locally and don't need to foresee any future changes of this value, because it is immutable.

Now we are familiar with variables, it's the perfect time to introduce the concept of a type. First, each variable has a type. The type defines the set of values which can be stored in a variable. Each type uses a different amount of the device's memory. Based on the type, the compiler knows how much space should be allocated when we declare a new variable.

In Swift, we define the type of a variable after the declaration of the variable itself. Our first code would look like this:

var text:String = "Hello World"
Is it mandatory to add a type declaration after each variable definition? No.

The Swift compiler is quite smart, and it infers the types based on the expressions on the right side. There are many examples which could illustrate how smart it is. But we should remember one: if the variable or constant is initialized, then we can simply omit the type. Of course, explicitly pointing to the type will make the code easier for other developers to understand. It's good to keep the same code style through all your code across every project. For some projects, it could be better if the type is omitted; for some, it may be worse.

Let's present all the basic types that Swift uses. The numbers are presented by several different types, based on the precision which is needed. The largest type takes extra memory, but it can store bigger values. The integer numbers can be stored in variables or constants from the following types: Int, Int8, Int16, Int32, Int64, UInt, UInt32, and UInt64. Floating-point numbers can be of the following types: Float, Float32, Float64, and Double. We are already familiar with the String type. It's used to store text in computer memory. Later, the text can be manipulated and presented to the user in different forms. The other quite popular data type is Bool, which takes exactly two values—true or false. We will discuss the need of boolean expressions later in this chapter, once we get familiar with conditional statements in Swift. We will define enumerable types and tuples. These are specific types that we can define, compared to the other ones, which are already defined for us.

Until now, we could declare variables or constants in one particular way. There are advanced ways to do this—one is to declare multiple variables on a single line, like this:

var a, b, sum: Double

All variables are from the same type, namely, Double.

We can specify a different type for each one, which gives us the freedom to declare variables/constants in a single shot on the same line.

The following code is an example of this:

var greeting: String, age:Int, money:Double

We can expand this even further by setting a default value, like in the following code:

var x:Double = 3.0, b:Bool = true

Of course, Swift is smart enough, so the following code has the very same meaning:

var x = 3.0, b = true

This automatic process is called type inference and greatly reduces the unnecessary boilerplate code which we would have to write.

Before diving into the details related to the different data types, we should know how to add comments to our code. Comments are blocks of text which are part of the source code, but they are removed when the source code is compiled.

The compilation is a complex process of transforming the code to machine code (in the case of Swift, it's something like this: Swift is converted to BitCode and this is converted to assembler, which is converted to machine language—low-level machine instructions which are understood by the hardware and are executed pretty quickly).

The comment's role is to clarify the code. There are two types of comments that we can use when we are developing a program in Swift. The first type is a single-row comment, which starts with // (double slash) and continues until the end of the row. Usually, developers prefer to start this comment on a new row or to add it to the end of a line, presenting a detail about the code, so it's easier for the reader to understand the encoded programming logic. The other type is a block comment, which starts with /* (slash and asterisk) and ends with */ (asterisk and slash). The comment can start anywhere, and continues until the matching ending sequence.

An interesting improvement from C++ or some other languages is that we can have several comment blocks which are nested in other comment blocks.

This is something new, which simplifies the process when we are adding comments.

When writing good code, try to add comments to make it easily understandable. In most cases, naming the variables with explicit names helps, but, usually, a brief comment is enough to clear the fog around a pretty complex sequence of your code.

Optional types

We are familiar with basic types and their forms, but now it's time to introduce the optional type(s). This is a new concept, compared to what we have in Objective-C, which helps developers to avoid common mistakes when they are working with data. To explain the optional type(s), we should present the problem they are solving.

When we are developing a program, we can declare a variable, and we should set it an initial value. Later in the code, we can use it. But this is not applicable in general. There may be some cases when the default value is to have NO-VALUE, or simply nil. This means that when we want to work with a variable which has NO-VALUE, we should check that. But if we forget the check, then while our app is executed, we can reach this strange state with NO-VALUE, and the app usually crashes. Also, the code which checks whether a variable contains a value is reduced, and the programming style is concise.

To summarize: optionals enforce better programming style and improve the code checking when the compiler does its job.

Now let's meet the optional types in the following code snippet:

var fiveOrNothing: Int? = 5
//we will discuss the if-statement later in this chapter
if let five = fiveOrNothing {
print(five);
} else {
print("There is no value!");
}

fiveOrNothing = nil

//we will discuss the if-statement later in this chapter

if let five = fiveOrNothing {
print(five);
} else {
print("There is no value!");
}

Every type we know so far has an optional version, if we can call it that. Later in the book, you will understand the whole magic behind the optional types; namely, how they are created. Here are some of those: String?, Bool?, Double?, Float?, and so on.

Until now, we have learned how to store data, but we don't know what kind of actions we can do with it. This is why we should get familiar with basic operations with the data. The operations are denoted with operators such as +, -, *, and /. These operations work with particular data types, and we have to do the conversion ourselves.

Let's check this code:

let number = 5
let divisor = 3
let remainder = number % divisor //remainder is again integer
let quotient = number / divisor // quotient is again integer

let hey = "Hi"
let greetingSwift = hey + " Swift 4!" //operator + concatenates strings