Skip to content

Introduction

Informations presented on this page may be incomplete or outdated. You can find the most up-to-date version reading my book Learn Swift by examples. Beginner level

Prepared and tested with Xcode 8.3 and Swift 3.1

Updated with Xcode 9.2 and Swift 4.1 new elements

In this tutorial we cover the following topics



Few words before we start

Swift is a totally new language. Any experience from other programming languges can help to lern it, but it is not an extension as Objective-C is an extension of C (event if it's not an extension, at least it's syntax is familiar for C programmers). In this Swift tutorial we assume that reader has some imperative programming language experience, so very basic ideas, like how a conditional statement if works, what a type conversion is, or what an error handling is about and what try-catch block means will be skiped. We will focus on

  • a new ideas (sometimes derived from Objective-C) specific for Swift language,
  • a new syntax of a well known ideas
  • .

Working with Swift for a short time, my opinion is that Swift is not a good programming language to start learning programming. It mixes many ideas from compiled and strong typed programming languages with ideas from script programming languages. In addition it contains many modern concepts. This makes a mixture of syntax which is very difficult to understand. What is worse, for Swift's novelty we have to pay with its complexity. Sometimes I have a thought that some madman took all programming ideas and put them all together without any reflection to the bag under the name Swift - for example please compare, available on my page, description of a protocols in Objective-C and Swift and you will know what I'm talking about.


Miscellaneous

Let's start with things to short to devote a separate section but too important to ignore them.

  • There is no ++ operator in Swift.
  • Swift provides two range operators unknown in C-like world, as a shortcut for expressing a range of values.
    • The closed range operator (a...b) defines a range that runs from a to b, including both values. The value of a must not be greater than b.
    • The half-open range operator (a..<b) defines a range that runs from a to b, but does not include b. The value of a must not be greater than b. If the value of a is equal to b, than the resulting range will be empty.
    • Starting from Swift 4 we can omit the upper or lower bound of a range specification to create a one-sided range


      ["four", "five"]
      ["four", "five"]
      ["one", "two", "three"]
      ["one", "two"]
  • Strings in Swift are value types which means that every time string is passed to a function or method, or when it is assigned to a constant or variable it's value is copied.
  • Moreover, in Swift, Array and Dictionary as String are all value types. They behave much like a simple int value in C, acting as a unique instance of that data. We don’t need to do anything special -- such as making an explicit copy -- to prevent other code from modifying that data behind our back. Importantly, we can safely pass copies of values across threads without synchronization. In the spirit of improving safety, this model will help us write more predictable code in Swift.
  • String interpolation is a method to construct a new string from a mixture of constants, variables, expressions and literals. Each item we combine into the string literal is wrapped in a pair of parentheses, prefixed by a backslash \().
  • Multi-line string literals. We can now create multi-line string literals, making it easy to produce precisely formatted text (e.g., JSON or HTML) directly into our source.


    first line;
    second line;
    third line;
    "quotation";
    just a text


Constants and variables

In Swift we use two keyword to say that ,,something'' is variable or constant (variables whose values cannot be changed): we use

  • let to say that it is a constant,
  • var to say thay it is a variable.

As we will see, Swift makes extensive use of constants. We can provide a type annotation when we declare constant or variable or we have to assign a value to allow compiler infer the type of constant or variable. So, to avoid Type annotation missing in pattern Swift compile error, instead of

we have to write

or

As we can see, Swift does not require us to write a semicolon after each statemet in our code, but we can do so if we want.

What is very important, once we've declared constant or variable of a certain type, we can't redeclare it, or change it to store values of different type. Nor can we change a constant into a variable or a variable into constant.

We can define multiple related variables of the same type on a single line


Tuples

Tuples is a well known concept from script programming languages and something I always want to have in C. Of course we can live without it and mimic with for example arrays or dictionaries but tuples are more natural. Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other.

If we don't care about the first element of a tuple, we can write it as

We can also use index numbers starting at zero to get tuple's element

To make our code more readable, we can name the individual elements in a tuple when the tuple is defined

Tuples are great for temporary usage. They are not suited to being use as a complex data structure persisting for a long time. In such a case structures and classes are better choice.


Optionals

Optionals are used in situations where a value may be absent. For example an optional integer is written as Int?.

We set an optional variable to a valueless state by assigning it the special value nil. Notice that Swift's nil is not the same as nil in Objective-C. In Objective-C nil is a pointer to a nonexistent object. In Swift, nil is not a pointer. It is the absence of a value of a certain type. Optionals of any type we want can be set to nil, not just object types. Conversely, nil cannot be used with nonoptionals. If a variable (rather constant) in our code needs to take no value, we have to declare it as an optional value of the appropriate type.

The key queston is: how we can use optionals? And the answer is not so obvious. We have few options

  • Simple guess and try approach

    doesn't work - we have Expression implicitly coerced from Int? to Any Swift compile warning in all of three prints and results are not such as we want (Optional(1) instead of 1)

    nil
    Optional(1)
    nil
  • If we are sure (but we have to be sure if we don't want to crash our application) that optional contains a non-nil value we can force unwrap its value with an exclamation mark added at the end of the optional's name
  • When working with optionals, if-else is something we must use. There is a special syntax we can use in this context. Optional binding is used to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable.

    Notice that for nonempty we don't have to use an exclamation mark.

    We can do even more: we can chain together multiple optional bindings, and the entire chain fails gracefully if any link in the chain is nil.

  • When we are sure that optional has some value every time we will use it, we can "remove" the need to check and unwrap the optional's value every time it is accessed thanks we can assume to have a value all of the time we need it. These kinds of optionals are defined as implicitly unwrapped optionals and we write it by placing an exclamation mark instead of question mark after the type we want to make optional.

    For example, this code

    in contrast to

    doesn't generate any warning or error and we can use implicitOptional variable without need of any explicit unwraping with an exclamation mark

  • Another handy tool we can use is the nil-coalescing operator ??. When used, for example in expression (a ?? b), it unwraps an optional a if it contains a value, or return a default value b if a is nil. The expression b must match the type that is stored inside a.

    The nil-coalescing operator is a shorthand for



Control flow

In Swift we may use all well-known control statements like if-then or while but with different than C-like syntax. We assume that reader is familiar with a variety of control flow statements, so only syntax is given.


1, 2, 3,
3, 2, 1,
***
+++
===


In Swift there is also a handy guard statement. We use guard to require that a condition must be true in order for the code after the guard statement to be executed. With no guard we do this with if but using a guard statement improves the readability.

For example, instead of

we can write something similar to

Why similar but not exactly like that? Notice that in the above if second print will be executed regardless of if's truth or falsity. With a guard there is no way to execute the code following this guard if condition is false. Swift force us to write the code so ther is no option to execute the code following the guard. In this case Xcode reports a compile error: 'guard' body may not fall through, consider using a 'return' or 'throw' to exit the scope.

If 'guard' body may not fall through, consider using a 'return' or 'throw' to exit the scope message confuses you, you can try to compare this code

and it's result


Condition met

with the following code

Because in the last program, the guard condition evaluates to false, again you will get an error 'guard' body may not fall through, consider using a 'return' or 'throw' to exit the scope.

You know nothing about functions yet, but this should be easy to follow and illustrative enough for this problem


someValue is equal to 5
Hello after function call

In Swift we can use labeled statements for loops or conditionals to explicitly say which of many nested loops / ifs we want to break or continue.


1 1 1
1 1 2
2 1 1
2 1 2
3 1 1
3 1 2

In Swift there is no need of break usage in switch's cases


Case ONE

If we want to use C-style fall through bahaviour a fallthrought keyword must be used. The fallthrough keyword causes code execution to move to the next case or default block.


Case ONE
Case TWO

Remember that doing that, the fallthrought does not check the case condition for the switch case that it causes execution to fall into.


1 or 2
3 or 4

Another improvement in Swift is an ability of switch's cases to check if their values are included in an interval.


Range two

Also tuples can be tested by case statement which can be very handy and allows to simplify our code


Point is inside the restricted area

Other things which may be useful is the ability to bind the value a switch matches to temporary constants or variables, to be used in the body of the case.


Point (0, 5.0) is on the OY axis


Eeee...



Enumerations

Enumerations should be well known to all programmers. An enumeration defines a common name for a group of related values and enables us to work with those values like any other type. In C language enumerations are very simple, allowing us to relate names to a set of integer values.

In Java we can do a lot more with enumerations


$ java Planet 175
Your weight on MERCURY is 66.107583
Your weight on VENUS is 158.374842
Your weight on EARTH is 175.000000
Your weight on MARS is 66.279007
Your weight on JUPITER is 442.847567
Your weight on SATURN is 186.552719
Your weight on URANUS is 158.397260
Your weight on NEPTUNE is 199.207413

In Swift enumerations are much like Java's enumerations. They incorporate many features usually supported by classes, such as (we will show all of them in class section of Swift tutorial)

  • computed properties to provide some additional informations about the current value of enumeration,
  • instance methods to provide functionality related to the values the enumeration represents,
  • initializers,
  • can be extended,
  • can conform to protocols.


Maybe one day you can live here
Make 10 step(s) forward
0
Mars is selected



Collections


Swift provides three primary collection types: arrays, sets and dictionaries. In Objective-C we have different types for mutable and immutable collections. In Swift every collection assigned to a variable is mutable and every collection assigned to a constant is immutable.


Arrays

An array stores values of the same type in an indexed order. The same value can appear in an array multiple times at different positions.


["Zero", "One", "Two"]
["zero", "one", "two"]

In Swift, differently than in Objective-C, we can't create an array that has pre-allocated memory but does not contain elements. We can't create an array of fixed, predefined size. A good news is that we can easily concatenate arrays.


["", "", "", "", ""]
["", "", "", "THREE", ""]
["zero", "one", "two", "", "", "", "THREE", ""]
["zero", "one", "two", "", "", "", "THREE", "", "FIVE", "SIX"]

We can use subscript syntax to change a range of values at once, even it the replacement set of values has a different length than the range we are replacing.


["zero", "ONE", "TWO", "THREE", "", "", "", "THREE", "", "FIVE", "SIX"]
["zero", "ONE", "TWO", "THREE", "***", "THREE", "", "FIVE", "SIX"]
["zero", "ONE", "TWO", "THREE", "THREE", "", "FIVE", "SIX"]
value: zero
value: ONE
value: TWO
value: THREE
value: THREE
value:
value: FIVE
value: SIX
at index: 0 value: zero
at index: 1 value: ONE
at index: 2 value: TWO
at index: 3 value: THREE
at index: 4 value: THREE
at index: 5 value:
at index: 6 value: FIVE
at index: 7 value: SIX

In Swift, to creating a multi-dimensional array we have to add another set of brackets. For example, to turn [Int] array into an array of arrays, we would just write [[Int]].


[[11, 12, 13, 14], [21, 22, 23], [31, 32]]
[[11, 12, 13, 14], [21, 22, 23, 24], [31, 32]]
[[11, 12, 13, 14], [21, 0, 23, 24], [31, 32]]


[[0, 0], [0, 0], [0, 0]]
[[0, 0], [0, 1], [0, 0]]


[[1, 2, 3], [4, 5, 6]]

We have to be very careful working with arrays in Swift -- generally, substitution with = operator makes a copy of an array.

For simple types such as integers and other structureswe have

If the elements in an array are instances of a class, the semantics are the same, though they might appear different at first.

More we can read in Array (Modifying Copies of Arrays).


Sets

A set stores distinc values of the same type in a collection with no defined ordering. We can use a set instead of an array when the order of elements is not relevant, or when we need to ensure that an element only appears once. A type of objects stored in a set must be hashable.


["one", "two"]
["one", "two"]
["one", "two"]
["one", "three"]
[2, 3, 1, 4]
[5, 6, 3, 4]
[5, 6, 2, 3, 1, 4]
[3, 4]
[2, 1]
[5, 6, 2, 1]

To test set membership or equality we can use

  • To test if two sets contain exactly the same values, we use == operator.
  • To test if all of the values of a set are contained in the specified set, we use isSubset(of:) method. We use isStrictSubset(of:) if we want to exclude equality of both sets.
  • To test if a set contains all of the values from a specified set, we use isSuperset(of:) method. We use isStrictSuperset(of:) if we want to exclude equality of both sets.
  • To test if both sets have no common values, we use isDisjoint(with:) method.


Dictionaries

A dictionary stores associations between keys (all of the same type) and values (all of the same but possible different than keys type) with no defined order. A dictionary key type must be hashable.


[:]
[:]
["digit0": "zero", "digit2": "two", "digit1": "one"]
["digit0": "zero", "digit2": "TwO", "digit1": "one"]


["digit0": "zero", "digit2": "TWO", "digit1": "one"]
Old value: TwO (Optional("TwO"))
["digit0": "zero", "digit2": "TWO", "digit1": "one", "digit3": "three"]
key: digit0 value: zero
key: digit2 value: TWO
key: digit1 value: one
key: digit3 value: three
key: digit0
key: digit2
key: digit1
key: digit3
value: zero
value: TWO
value: one
value: three

Swift 4 brings a number of improvements to make dictionaries more powerful, useful and usable.

Sequence-based initializer.
We can now create dictionaries from a sequence of key-value pairs.


[2: "two", 3: "three", 1: "one", 4: "four"]
["three": 3, "four": 4, "one": 1, "two": 2]

Merging
Dictionary now includes an initializer that allows us to merge two dictionaries together. If we want to merge one dictionary into another, Swift also provides a merge(_:uniquingKeysWith:) method. Both allow us to specify a closure to resolve merge conflicts caused by duplicate keys.


["b": 2, "a": 1, "c": 4]
[("a", 1), ("b", 2), ("a", 3), ("c", 4)]

More details can be found for example in How to work with Dictionaries in Swift 4.


Working with sequences

In Swift we can use zip(_:_) function to create a sequence of pairs built out of two underlying sequences.


one: 1
two: 2
three: 3
four: 4

If the two sequences passed to zip(_:_:) are different lengths, the resulting sequence is the same length as the shorter sequence. In this example, the resulting array is the same length as words:


[("one", 1), ("two", 2), ("three", 3), ("four", 4)]

We can use map(_) function which returns an array containing the results of mapping the given closure over the sequence’s elements.


["ONE", "TWO", "THREE", "FOUR"]
[3, 3, 5, 4]

We can use filter(_:) function which returns an array containing, in order, the elements of the sequence that satisfy the given predicate.


["three", "four"]

We can use reduce(_:_:) function which returns the result of combining the elements of the sequence using the given closure.


10
10

More details about map, filter and reduce can be found in Swift Guide to Map Filter Reduce