Learn Swift by Building Applications

3.8 (4 reviews total)
By Emil Atanasov
    What do you get with a Packt Subscription?

  • Instant access to this title and 7,500+ eBooks & Videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Swift Basics – Variables and Functions

About 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.

Publication date:
May 2018
Publisher
Packt
Pages
366
ISBN
9781786463920

 

Swift Basics – Variables and Functions

In this chapter, we will present the basics of the Swift language, starting from square one: introducing the basic concepts. The code, which is part of the chapter, illustrates the topics under discussion. In the next chapter, we will learn how to execute code samples in Xcode.

Let's begin with a brief history of Swift. This is a brand new programming language, developed by Apple and announced in 2014. In 2016, Swift 3 was released as open source, and this is the first major version, which enables people interested in Swift to develop the language. This means only one thing: Swift will start spreading even faster, beyond Apple's ecosystem. In this book, we will give examples of Swift, and we will discuss most of our solutions related to iOS, but you should know that the knowledge here is applicable across all places where Swift code is used.

Before diving into real code, let's define some basic concepts that we can use later in the book.

What is a computer program or application (app)? Simply, we can think of an app as a set of computer instructions that can be executed. Each app has a source code, written in a language describing all actions that the program does. In our case, we will write mobile (iOS) apps in Swift.

There are many low-level computer instructions, but Swift helps us to write without hassle, without knowing much about the low-level organization. Now we will start with the basic concept of variables.

We will discuss the following topics:

  • Constants and variables
  • Initializing using expressions
  • Basic types in Swift
  • Optional types
  • Enumeration types
  • Code flow statements – if, switch, loops
  • Functions
  • Tuples
  • The guard statement
  • Top-down and bottom-up

We begin with the basic building blocks of all programs.

 

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
 

Enumeration types

In Swift, we can define simple types which have limited possible different values. These types are enumerations. We define them with the keyword enum. The following code is an example of this:

enum AnEnumeration {
// the value definitions goes here
}

Here's another code that does this:

enum GameInputDevice 
case keyboard, joystick, mouse
}

The code has three different enumeration cases. All cases may appear on a single line, such as in the preceding code, or even one by one on a line.

We can meet the following notation, because Swift infers the missing part:

var input = GameInputDevice.mouse
//...
//later in the code
input = .joystick
The code bundle for the book is hosted on GitHub at https://github.com/PacktPublishing/Learn-Swift-by-Building-Applications. In case there's an update to the code, it will be updated on the existing GitHub repository.
 

Basic flow statements

What are basic flow statements? These are several statements which help you to structure the program code in a way that allows you to do different action(s) based on the data stored in particular variables. We will learn how to execute just part of the code if a certain condition is met (the condition could be a pretty complex Boolean expression). Then, we will find a way to execute different actions several times in a loop. The next thing will be to learn how to repeat things until a condition is met and to stop executing statements once the condition is not satisfied. Using flow-control statements, we can construct pretty complex code chunks, similar to what we can express with regular text writing. To develop a program, we should first create an algorithm (a sequence of steps) which leads to the desired result, taking into account all external and internal conditions. Based on this sequence, we can then develop a program, using all flow operators. But let's get familiar with some forms of them.

The if statements – how to control the code flow

This is how we can branch our code logic based on some data stored in a variable:

let num = 5
if num % 2 == 0 {
print("The number \(num) is even.")
} else {
print("The number \(num) is odd.")
}

The general pattern of an if statement is organized as follows:

var logicalCheck = 7 > 5
if (logicalCheck) {
//code which will be executed if the logical check is evaluated to true
} else {
//code which will be executed if the logical check is evaluated to false
}

We know that the if clause gives us huge freedom to shape the code that will be executed (evaluated). An application may handle many different cases, but only the code that fulfills the conditions encoded in our solution will be triggered.

Loops

Let's learn how to implement repetitive tasks. There are several ways to do that, using different loops: while, for...in, and repeat...while. The most popular one is the for...in loop. Here is what the basic form looks like:

let collection = [1, 2, 3]
for variable in collection {
//do some action
}

The code will be interpreted like this: the variable will be set to all possible values, which are stored in the collection. If the collection is empty, then no code will be executed. If there are some elements, then the body of the loop (the code in curly braces) will be executed for each element of the collection. The variable loops through every single element and can be used in code.

We need an example to illustrate this. Let's use the following code to print all numbers from 1 to 10, inclusive:

var sum = 0
for index in 1...10 {
sum += index
print("(index)")
}
print("Sum: \(sum)")
//sum is equal to 55

The sum of all numbers from 1 to 10 is stored in a separate variable and the code prints every single number on a new line. The sequence defined with 1...10 is converted to a collection (we can think of it as an array), which is fueling the for...in loop.

We can use variables or constants to define custom ranges of numbers.

Take a look at the following code:

let threeTimes = 3
for _ in 1...threeTimes {
print("Print this message.")
}

Using _ (underscore) we declare that the argument should ignore the values set in the variable, and it doesn't matter to the rest of the code. The code will print three times: Print this message.

The while loops

The while loops execute the body of the loop (list of the statements in the body part) until the condition is evaluated to false.

There are two types of while loops. There is the classical while loop, which checks the condition, and, if it holds, then the code in the body is executed. Then the check is performed again and everything is repeated until the condition is evaluated to false. The other variant is the repeat...while loop, which first executes the body, and then does the check. The second type is executed at least once, compared to the first one, which could be completely skipped:

var i = 1
let max = 10
var sum = 0
while i <= max {
sum += i
i += 1
}
print("Sum: \(sum)")

The code sums all numbers from 1 to 10. The condition will be broken once i reaches 11.

We can use repeat...while to do the same:

var i = 1
let max = 10
var sum = 0
repeat {
sum += i
i += 1
} while i <= max
print("Sum: \(sum)")

We can use while to implement the repeat...while loops and the reverse, but with slight modifications. The best rule for picking the right type of loop is to know whether the sequence should be executed at least once. Executing once means that it's much easier to implement it using repeat...while; otherwise, the classical while loop is the best choice.

There are some special conditions which we should handle, but to do so, let's see what they are.

We can use the special words—continue and break—to trigger special behavior while we are in a loop. The continue statement is used when you want to stop the current iteration of the loop and start over. When using this, be careful that you change the value in the condition; otherwise, the loop could be an infinite one, which means that your program won't end.

The break statement is used once we want to stop the entire loop. Be careful when you have nested loops. The break statement stops the current iteration immediately, and then jumps to the very first line after the end of the innermost loop, which contains the break statement. If you want to break two or more nested loops, then you have to find an appropriate way to do so. To be explicit when breaking nested loops, you may use labeled statements. It is a convenient way to give a name of a loop and then to change the flow when using break. It's good to know that break may be used as part of a switch statement. This will be discussed in the next part.

There are a few other special words, such as return , throw, and fallthrough which change the default order of execution of the code. We will get familiar with these later.

The switch statement

A switch statement is a concise way to describe a situation where we have several possible options to pick from and we don't want to write a lot of boilerplate code using the already familiar if statement.

Here is the general pattern of a switch statement (please note that this is not a valid Swift code):

switch a-variable-to-be-matched {
case value-1:
//code which will be executed, if variable has value-1
//we need at least one valid executable statement here
(comments are not an executable statement)
case value-2,
value-3:
//code which will be executed, if variable has value-2 or value-3
default:
//code which will be executed, if variable has value different
from all listed cases
}

What we see is that switch has many possible cases, each one starting with the special word case, and then a specific value. Swift supports specific value matching, but it supports more complex rules for pattern matching. Each case could be considered as a separate if statement. If one case is activated, then all others are skipped. The default case is a specific one and is triggered if there is no match with any other case. The default case appears at the end, and it's defined with the special word default.

We can use break to interrupt execution of the code in a case statement. If we want to have an empty case statement, it's good to add break.

We have some specifics with the implementation of switch in Swift, which are new when compared to the other programming languages, but they improve the readability of the code. First, there is now a way to have an empty body of a specific case. To be correct, we have to add at least one valid statement after the case. There is no implicit fallthrough after each case. This means that once the last executable statement in a case branch is triggered, we are continuing after the switch statement. Nothing else that is part of the switch statement will be executed. We could consider that every case statement has a hidden break at its very end. Next, we need the special word fallthrough to simulate the regular behavior of the switch. Another interesting thing is that we can have interval matching, tuples matching, and value bindings. Finally, we can use the where clause if we want to express some dependency between the data which should be matched. It's also possible to list several cases if they have to share the code which should be executed. They have to be separated with ,.

Here is code that shows how easy and smart switch is:

let point = (1, 1)
switch point {
case let (x, y) where x == y:
print("X is \(x). Y is \(y). They have the same value.");
case (1, let y):
print("X is 1. Y is \(y). They could be different.");
case (let x, 1):
print("X is \(x). Y is 1. They could be different.");
case let (x, y) where x > y:
print("X is \(x). Y is \(y). X is greater than Y.");
default:
print("Are you sure?")
}
 

Functions

In this section, we will learn how to define functions and how to use them in our code. They help us to reuse sequences of statements with ease. We can define a general solution of a problem and then apply it, customized, to different parts of our app. This approach saves time, reduces the potential of bugs in the code, and simplifies huge problems to small ones.

The first function, which we already saw in use, is print(). It's used to display text on the screen. We will experiment with this in the next chapter, once we get our hands dirty with Xcode and Swift.

Now let's define our first function, which executes a sequence of statements in its body:

func printSum() {
let a = 3
let b = 4
print("Sum \(a) + \(b) = \(a + b)")
}

When defining a function, we start with the special word func. Then the name of the function follows and the list of the arguments in brackets ( ) and its returned type. After that comes the body of the function in curly braces { }.

The name can start with any letter or underscore and can be followed by a letter, digit, underscore, or dollar sign. A function name shouldn't match any keyword from the Swift language.

This definition doesn't do anything if we don't call (execute) the function. How is this done?

We have to call the function using its own name as follows:

printSum()

Once a function is called, we may think that the same sequence of code is executed where the function call is made. It's not exactly the same, but we can think of having the body of the function executed line by line.

Now let's see the general form of a function:

func functionName(argumentLabel variableName:String) -> String {
let returnedValue = variableName + " was passed"
return returnedValue
}
//here is the function invocation and how the result is returned
let resultOfFunctionCall = functionName(argumentLabel: "Nothing")

Each function may have no arguments, one argument, or many arguments. Until now, we have seen some without arguments and with a single argument. Every argument has an argument label and a parameter name. The argument label is used when the function is called. This is really useful when we have many parameters. It gives us a clue what data should be passed to that specific parameter when using the function. The parameter name (variable name) is the name which will be used in the function body to refer to the passed value. All parameters should have unique parameter names; otherwise there is ambiguity, and we won't be able to say which one is which.

A function may return a value from a specific type, or it may be void (nothing will be returned). When we want to return something, we have to define that, and this is done with -> and the type of the result. In the preceding code, we see -> String, and this means that the function returns a value of the String type. This obliges/binds us to using the keyword return in the function body at least once. The return keyword immediately stops the execution of the function and returns the value passed. If a function doesn't return anything, we can still use return in its body, and it will work similarly to break in a loop.

We can use _ if we want to skip the label of an argument. Here is a simple piece of code that illustrates that:

func concatenateStrings(_ s1:String, _ s2:String) -> String {
return s1 + s2
}
let helloSwift = concatenateStrings("Hello ", "Swift!")
// or
concatenateStrings("Hello ", "Swift!")

When we don't use the _ (underscore), then the argument name is the same as the parameter name (variable name).

Similar to what we have seen with the labels, we can ignore the returned value once the function is called.

What happens if we want to return multiple values? We can use tuples to return multiple values when executing a function. The following code is an example of this:

//define a function which finds the max element and its index in an 
array of integers
func maxItemIndex(numbers:[Int]) -> (item:Int, index:Int) {
var index = -1
var max = Int.min
//use this fancy notation to attach an index to each item
for (i, val) in numbers.enumerated() {
if max < val {
max = val
index = i
}
}

return (max, index)
}

let maxItemTuple = maxItemIndex(numbers: [12, 2, 6, 3, 4, 5, 2, 10])
if maxItemTuple.index >= 0 {
print("Max item is \(maxItemTuple.item).")
}
//prints "Max item is 12."

What is a tuple?

A tuple is a bundle of different types (they may be the same) which have short names. In the preceding code, we have a tuple of two Int statements. The first one is named item, and the second one is named index. After the execution of the function, we will store the maximum item and its index in the tuple. If there are no items in the array, then the index will be -1.

It's possible to return an optional tuple type if there is a chance to return nil in some cases. The previous function may return nil if there are no items, and a valid result otherwise.

Each parameter may have a default value set. To set a default value, you have to declare it and add it right after the parameter's type. The following code is an example of this:

func generateGreeting(greet:String, thing:String = "world") -> String {
return greet + thing + "!"
}

print(generateGreeting(greet: "Hello "))
print(generateGreeting(greet: "Hello ", thing: " Swift 4"))

We can easily define a function which accepts zero or more variables of a specified type. This is called a variadic parameter. Each function definition could have, at most, one variadic parameter. It's denoted with ... after its type. In the body of the function, the type of this parameter is converted to an array. This array contains all passed values:

func maxValue(_ numbers:Int...) -> Int {
var max = Int.min
for v in numbers {
if max < v {
max = v
}
}

return max
}

print(maxValue(1, 2, 3, 4, 5))
//prints 5

One specific thing that we should know about function parameters is that they are constants. We can't mutate these by mistake. We should express this explicitly. To do so, we have to use the special word inout to mark the parameter. The inout parameters is added before the type of the parameter. We can pass variables to the inout parameters, but we can't pass constants. To pass a variable, we should mark this with & when calling the function. The inout parameters can't have default values. Also, variadic parameters can't be marked as such. In general, we can use the inout parameters to return values from a function, but this is not the same as returning values using return. This is an alternative way to let a function affect the outer world in the matrix. Check out the following code:

func updateVar(_ x: inout Int, newValue: Int = 5) {
x = newValue
}

var ten = 10
print(ten)
updateVar(&ten, newValue: 15)
print(ten)

What is the guard statement?

The guard statement has similar behavior to an if statement. This statement checks the condition, and if it's not met, then the else clause is triggered. In the else clause, the developer should finish the current function or program, because the prerequisites won't be met. Take a look at the following code:

func generateGreeting(_ greeting: String?) -> String {
guard let greeting = greeting else {
//there is no greeting, we return something and finish
return "No greeting :("
}
//there is a greeting and we generate a greeting message
return greeting + " Swift 4!"
}

print(generateGreeting(nil))
print(generateGreeting("Hey"))

This is a tiny example, showing us code that illustrates the regular usage of the guard statement. We can combine it with the where clause, or we can make the check really complex. Usually, it's used when the code depends on several if...let checks. The guard statement keeps the code concise.

How to tackle huge problems – bottom-up versus top-down

Step-by-step through this book, we will start solving problems until we can write a fully-working mobile app. It's not an easy task, but we can take two different approaches when trying to solve a huge problem (such as writing a mobile app). The first one is top-down. This technique starts from the top with the main problem, and breaks it down into smaller problems and functions. Once we reach something unclear, something which is not well defined that we should implement, then we define a new function, but we won't continue developing the exact implementation of this part of the app immediately. Let's assume that we are trying to develop a mobile app with three screens. The first one displays a list of news. The second one renders specific news, and the last one shows information about our application.

If we apply the top-down approach, then we will have the following abstract process. We start from the biggest problem: how to develop an app with three screens. Then, we break this huge task down into three sub-tasks with their respective functions. Those functions are empty functions. The first one will be responsible for creating the first screen, the second one should create the detailed news presentation, and the third should define the last screen. By doing this, we have decomposed the main problem into three smaller ones. These new functions are empty, but at a later phase we will implement each one of them. We can start with the first one: we define another help function which creates the list of news, and another function which fetches the news from an internet address. Now it doesn't look really hard to define those functions. We will learn how to do this throughout the book, but the general idea is to break down each problem into smaller ones until you reach a state where you can solve them without any hassle. In the end, the main problem will be solved, because all parts that have been decomposed are already working, and the final result will be a fully-working mobile application.

The other approach is bottom-up, which does things in reverse. It's more like working with Lego, but you first go and build many small building blocks, which you combine together until you manage to build a solution to the whole problem; in our case, until you build a working mobile app. Abstractly, we develop simple enough functions that we can implement to solve small problems. Then we combine those into bigger chunks. Those bigger chunks are put together in even bigger and more complex functions or app parts, until we define the final working app.

Neither of these two approaches is the best. Every developer prefers to use a nice mixture of both techniques, which leads to the final result—a working app.


If top-down, or bottom-up, is used on its own, it is not a silver bullet. Try to use top-down and bottom-up together and you will find the solution easier.

Just tweak your approach based on what you know at the moment, and what you have.

 

Summary

In this chapter, we became familiar with Swift 4 basics. We now know what variables and constants are. We can use basic types, the if and switch statements, and loops, and we can define functions. These are the smallest key building blocks that we will need to start our adventure in Swift 4 and the iOS/macOS/watchOS world.

In the next chapter, you will become familiar with Xcode—the development environment software that is really handy when we are writing code in Swift. You will develop your first playground, which is a nice tool to check and demo the code. You can use everything learned in this chapter, and, in the end, you will be familiar with how to add descriptions using a markup language to make your playgrounds and functions well documented. Don't spend a minute more—find a macOS and move to the next chapter to get your hands dirty with some real code.

About the Author

  • Emil Atanasov

    Emil Atanasov is an IT consultant who has extensive experience with mobile technologies. He started working in the field of mobile development in 2006. He runs his own contracting and consulting company, serving clients from around the world—Appose Studio Inc. He is an MSc graduate from RWTH Aachen University, Germany, and Sofia University "St. Kliment Ohridski", Bulgaria. He has been a contractor for several large companies in the US and UK, serving variously as team leader, project manager, iOS developer, and Android developer.

    Browse publications by this author

Latest Reviews

(4 reviews total)
Excellent copy. Easy to understand. Thank You
Love the book. It is a little more advanced than I expected, so I am proceeding a little slower.
Présentement, je trouve que le livre est parfaitement structuré.
Learn Swift by Building Applications
Unlock this book and the full library FREE for 7 days
Start now