2.
Beginning Swift
Written by Sarah Reichelt
In the first chapter, you installed Xcode and configured it. Then, you learned how to create a Mac app from the standard template.
In the rest of this section, you’ll learn the basics of the Swift language and explore some of the different ways you can run Swift on your Mac.
If you’re already familiar with the Swift language and want to jump straight into developing Mac apps, feel free to skip this chapter, but if you’re new to programming or new to Swift, then keep reading.
What is Swift?
Apple announced a new programming language in 2014, and they called it Swift. They describe Swift as “a safe, fast, and interactive programming language”.
Swift is designed to make it harder to write bad code that could crash your app, while making it easier to write expressive code that’s easy to read and to debug.
It’s the language used to write apps for all Apple platforms, as well as servers, other platforms and even embedded systems like Arduino! But enough talk — time to code.
Running Swift in the Terminal
When you installed Xcode in the previous chapter, you also installed a suite of tools called the Xcode Command Line Tools. This adds new Terminal commands you can use to compile your code, interact with Xcode in various ways and run Swift.
Open Terminal by going to Applications ▸ Utilities ▸ Terminal.app or by pressing Command-Space to open Spotlight and searching for Terminal. The default Terminal window opens as a small window in the top left of your screen. The width is fine, but expand the window so that it’s as tall as your screen. This makes it much easier to see the sequence of commands that you’re about to run.
In Terminal, type swift and press Return:
You’re looking at a list of the subcommands that you can run from the swift command line tool. Most of these are to do with packages, which are beyond the scope of this book. The one you’re interested in is repl so that you can “experiment with Swift code interactively”.
Type swift repl and press Return to start the Swift REPL. So what is a REPL? It stands for Read-Evaluate-Print-Loop. You type in Swift code, the Swift REPL reads it, evaluates the result, prints that result and loops back to its command prompt ready for another command.
Note: In earlier versions of the Xcode Command Line Tools, running
swiftwithout any extra arguments automatically started the Swift REPL, but since Swift 5.7, you need to select this manually.
To get out of the REPL and back to your usual Terminal, enter :exit or press Control-D. Pressing Command-K at any time clears the Terminal screen.
If you exited the REPL, press Up-Arrow to return to the previous command and run swift repl again.
Swift Types
Swift is a strictly-typed language, but what does that mean? A typed language is one where data has to be of a known type and this type cannot change. Swift infers the data type depending on what you give it and the Swift REPL makes it easy to see the assigned type.
In the REPL, type 1 and press Return:
You only entered one character, but there’s a lot of information on this screen:
- The first line shows your standard Terminal prompt — in my case, it’s showing my user name and computer name — followed by the command you entered to start the REPL.
- You get to see what version of Swift you’re running. Don’t worry if it’s not exactly the same as mine.
- The REPL has its own prompt which numbers the lines as you enter them. You typed
1on line 1. - This is where the REPL printed the result. First, you see $R0 which is an internal label that the REPL assigns to your result. Then you see Int = 1. This tells you that Swift has evaluated what you entered and found it to be an integer with the value of 1. Swift uses
Intto indicate an integer, which is a whole number with no decimal point. - Finally, the REPL loops back and gives you another prompt.
Now that you know how to read what the REPL tells you, enter these lines, pressing Return after each one:
4.87
"Swift"
true
Checking the results of these lines, by line number:
-
Doubleis short for double precision floating point and means a number with decimals. As you can see from the printed result, computers aren’t very good at floating point numbers and often get them a bit wrong, although rarely enough to make any significant difference. -
Stringdescribes any text and, in Swift, you surround text with double-quotes. -
Bool(short forBoolean) is a value that can only be eithertrueorfalse.
These four entries demonstrate the basic or primitive types used by Swift. Later, you’ll see how to combine these into more complex types for your own data needs.
Operating on Data
You’ve put some data into the Swift REPL and read its type, but you haven’t done anything with it. You’ll use operators to perform operations on your data. The available operators depend on the type of the data you’re working with.
Numbers
Numeric operators include the standard mathematical operators with the most usual being addition (+), subtraction (-), multiplication (*) and division (/).
Evaluate these commands one at a time in the Swift REPL:
67 + 3
1.45 - 2
9 * 4
7 / 3
Which gives these results:
Looking at these by line number:
- Adding 2
Intvalues returns anotherInt. - The first value here is a
Double. You can only subtract aDoublefrom anotherDouble, so Swift has assigned a type ofDoubleto the 2. The result is aDoubleand again shows the problems a computer can have with decimals. - Again, this operator started with two
Intvalues and gives anotherInt. - This one may have surprised you with what appears to be the wrong answer. Shouldn’t 7 divided by 3 equal 2.3333333? Not in this case, because you started with two
Intvalues and so Swift performed an integer operation and returned an integer value. To get the correct answer, enter7.0 / 3. To our human eyes, 7.0 is exactly the same as 7, but to Swift, one is aDoubleand one is anInt.
Note: The spaces either side of the operator make the expression easier to read. Omitting both spaces —
9*4— will work, but if you put a space on one side, make sure there’s a space on the other side.9 *4or9* 4won’t work. If you use inconsistent spacing, Swift shows a very unhelpful error message: error: consecutive statements on a line must be separated by ‘;’, so if you see that, check your spaces.
Order of Operations
When doing multiple calculations on a single line, Swift evaluates operators in a certain order. Type in this operation, but before pressing Return, try to work out what result you expect:
2 + 5 * 3
If you worked from left to right, you may have expected 21 (2 + 5 = 7, 7 * 3 = 21). But the order of operations dictates that multiplication and division happen first and then addition and subtraction. So for this sum, 5 * 3 = 15, 2 + 15 = 17.
If you want to change the order, wrap sections in parentheses. Swift evaluates these sections first and then evaluates the rest of the line. To get 21, you’d need to do this:
(2 + 5) * 3
While you can rely on the order of operations, you can always use parentheses to make your meaning clear.
Strings
You can operate on String data too. The + operator concatenates strings. Run this command:
"Hello" + " Swift!"
You’ll get a single String with the two parts run together. There’s a space before the S in the second string to make sure the words aren’t run together. The + operator does not add a space.
Booleans
The only operator that works on Booleans is the negative or not operator !. You can see it in action like this:
!true
It toggles true to false and false to true.
Storing Data
So far, you’ve used the Swift REPL in a very transitory way. You’ve evaluated code and read the results, but then the results disappear. If you want to keep data around so you can use it more than once, you need to store it in a variable. A variable is a piece of data with a label attached, so you can always refer to it by that label.
Still in the REPL, enter:
var language = "Swift"
The REPL reports back that language is a String, which is correct. It also shows that instead of giving it a temporary $R label, it has assigned it to a variable called language. Now you can use that variable:
"Hello " + language
You’ve printed your String variable with a prefix, but you haven’t changed the language variable, which you can prove by evaluating language on its own.
To change a variable, store the result of your operation back into the same variable, like this:
language = "Hello " + language
This line says to set the contents of the language variable to “Hello “ followed by whatever was in there before.
Now when you evaluate language (you can press Up-Arrow to bring back your previous commands), you’ll see that it has changed:
You already know that Swift assigns types to data. It does the same to variables, and once assigned, these types can’t be changed.
Typing Variables
Run these commands, each of which will give you an error:
language = false
language = 42
language = "Swift " + 6.2
The first two errors say that you cannot assign a value of a different type to a String variable. The last one tells you that a Double cannot be converted to the expected argument type String. As you saw earlier, + is a valid String operator and a valid numeric operator, but it only works if it gets the same type of data on both sides.
Swift uses Type Inference to decide what sort of data you’re using. You can set the types manually if you want to, but it’s better practice to let Swift infer the types for you whenever possible.
To specify the type, follow the variable name with a colon and then the data type, like this:
var userName: String = "admin"
var isLoggedIn: Bool = true
var counter: Int = 0
var width: Float = 5.64
In these examples, the first three type declarations are redundant since Swift would have allocated those exact types. In the fourth line, the type is different to the default Double type for a floating point number, so this is an example of where you do need to specify the type manually.
A Float is a single precision floating point number so it’s similar to a Double but it can’t hold numbers as big or as small. It takes up less memory but unless you’re writing code for a system where memory usage is critical, it’s easier to let Swift make the choices and stick to using Double.
Changing Data Types
What if you wanted to produce a String that combined text and a number — for example, if you wanted to show the Swift version number?
You use String Interpolation. This is a way of inserting the result of any Swift operation into a String. You use it by creating a quoted string as usual, and then adding the insertion wrapped in \( and ) like this:
var version = 6.2
language = "Swift \(version)"
Now when you print out the language variable, you’ll see that it contains “Swift 6.2”.
You can insert almost anything inside a string interpolation, including numbers, other strings, calculations and variables.
So that covers creating strings, but what about converting numbers between the different numeric formats?
Evaluate these three lines and see what happens:
var score = 6.8
var bonusPoints = 3
score += bonusPoints
Stepping through these lines as numbered in the screenshot:
-
scoreis aDoubleand is almost equal to the number you entered. -
bonusPointsis anInt. - You’re trying to add an
Intto aDouble.
The += operator is a shorthand way of saying score = score + bonusPoints. You can also use -=, *= and /=. They look strange at first, but once you get used to them, these operators allow you to write code that is neat and efficient.
As before, the last line gives a “cannot convert” error because you’ve got two different types on either side of the operator. To make this work, you have to change one of these values to the same type as the other. You could use Int(score) to convert score to an integer. It would lose precision and become 6, but the addition would work.
In this case, a better solution is to convert bonusPoints to a Double using Double(bonusPoints). This command works:
score += Double(bonusPoints)
These Int() and Double() commands are initializers. They’re initializing a new instance of their data type starting with the supplied value.
Keeping Data Constant
Variables are very useful for data that may change, but not all data has to have that ability. Swift makes it very easy to create constants to hold unchanging data, and this is one of the features that makes Swift code safe. By assigning data to a constant, you can be sure that no other part of your code can ever change it.
Assigning a constant is similar to assigning a variable, but you use the let keyword instead of var:
let userID = "ABCD1234"
Note: If you’ve come from the JavaScript world, this is the opposite of what you expect, but
letin Swift is the same asconstin JavaScript, whilevarin Swift is likeletin JavaScript.
A good rule of thumb when coding in Swift is to start with let for every piece of data and only change to var if Xcode complains.
Trying to edit a constant gives a series of errors, which helpfully tell you what to do if you actually need to edit the value:
Naming Variables
When you’re writing code, it’s important to make it readable. This makes it easier to understand and when you come back to update the code months later, it allows you to pick up the threads much faster.
Swift encourages code that reads well and a big part of that is choosing good variable names. Compare these two chunks of code:
let u = "ABCD1234"
var n = "Jane Doe"
var pw = "super_secret"
var p = 36
let userID = "ABCD1234"
var userName = "Jane Doe"
var password = "super_secret"
var parkingSpaceNumber = 36
Which one would you rather read if you were unfamiliar with the code? Xcode and the Swift REPL have excellent auto-complete options. To see this in action, go back to the Swift REPL, type l and press Tab:
Because you previously defined the language variable, auto-complete suggests it, along with two key words that also match what you typed.
Type an after the l it filled in for you on the next line and this time, pressing Tab gives your full variable name. Press Return to evaluate it.
So there’s no excuse for writing short and unhelpful names as they don’t actually save you any time when writing and they’ll cost you a lot more time later.
You can use this auto-complete technique for the rest of this chapter to make your life easier as you type in the REPL.
The convention for writing variable and constant names in Swift is lowerCamelCase. Names start with a lowercase letter and the subsequent words in the name start with an uppercase letter.
Swift allows for a great deal of variety in variable names including the use of Emoji, but in the interests of clarity, this isn’t a great idea. Variable names must start with a letter, but after that, they can contain letters, numbers, underscores and dashes.
Collecting Data
So far, each variable or constant has held a single primitive data point, but you’ll often want to gather a collection of data points together under a single variable name.
Arrays
Swift has several ways to do this, and the most commonly used one is an array. An array is an ordered collection of items of the same type.
To create an array, you wrap the data in square brackets and separate the individual items by commas:
var things = [ "pear", "banana", "grape", "zebra" ]
When you run this line in the REPL, you’ll see that things has the type [String]. The square brackets indicate that it’s an array and the String says that the elements in the array are all of type String. To us, “grape” and “zebra” are very different, but to Swift, they’re both strings and that makes them similar enough to have in the same array.
Arrays have operations, too. The + operator combines two arrays:
things += [ "aardvark", "artichoke" ]
print(things)
things now has six elements:
Note: In the REPL, you can check the value of a variable by entering its name and pressing Return. That gives a lot of information about the variable and its contents. For a more compact display, you can use
To access a single item in an array — commonly referred to as an element — you use its position, or index, in the array. The things array has six elements, but computers like to start counting from zero, so the first element has an index of zero.
Run these commands one at a time, but beware — one of them will crash the REPL:
things[0]
things[5]
things[6]
The last line gave Fatal error: Index out of range which is what happens when you try to read an element that doesn’t exist. The key point to remember is that the last element has an index that’s equal to the number of elements minus one.
Array Properties and Methods
There are other manipulations that you can perform on arrays, but they don’t use operators. Instead, they use methods and properties. Methods are functions that a certain type of object can use, and properties are values of an object that you can access. You’ll learn more about these in later chapters, but for now, check these different array properties and methods:
var companions: [String] = []
companions.append("Sarah Jane")
companions += ["Amelia", "Rose", "Martha", "Donna"]
print(companions)
companions.count
companions.remove(at: 2)
print(companions)
Going through these different commands:
- When you create an array with starting data, Swift uses the initial elements to decide the type of the whole array. When starting with an empty array, you must declare the type inside square brackets and then initialize the array as empty with the second set of square brackets after the equals sign.
- The
appendmethod adds a new element on to the end of the array. The new element has to match the declared type for the array, in this case aString. - As you saw already, the
+operator merges two arrays, and you can use the+=shorthand here too. - The
printcommand displays the contents of the array. - Query the
countproperty to see how long the array is. - Use
remove(at:)to delete the element at the specified index. If you use an index that doesn’t exist, you’ll get another fatal error. - Bonus points if you spotted the Doctor Who reference. :]
Arrays are a useful data structure for storing a list of items of the same type and accessing them by index, but what if you wanted to be able to access the elements by name? For that, you need to use a dictionary.
Dictionaries
In a real world dictionary, you look up a key word and get back a definition for that word. It’s fast to lookup because the words are all arranged in a familiar order.
In Swift, dictionaries are very similar. Each entry in a dictionary has a key and a value. The key is like the word that you look up and the value is the definition. Internally, Swift stores the keys very efficiently so it can look them up very fast.
These keys and values can be of any type so long as all the keys are the same type and all the values are the same type. The keys and values don’t have to be the same type. Commonly, the keys are strings.
Imagine you’re out on a bird-spotting walk carrying your Mac with you. Run these examples one by one in the REPL:
var birdsSeen: [String: Int] = [:]
birdsSeen["Robin"] = 3
birdsSeen["Blue Jay"] = 27
print(birdsSeen)
Following this sequence:
- When creating an empty dictionary you have to set the types for both the keys and the values. Inside the square brackets, the type before the colon is for the key and the type after is for the value. After the equals sign, the square brackets with a colon inside set up an empty dictionary, or as the REPL reports, a dictionary with 0 key/value pairs.
- You add an element to an array by setting a particular key for the dictionary to a value of the correct type.
- Lines 9 and 10 in the image above set integers as the values for two different keys.
- Printing out the dictionary shows the entered data — yours may appear in a different order.
You retrieve values using their keys:
birdsSeen["Blue Jay"]
birdsSeen["Albatross"]
Interestingly, unlike with an array, you can request an item that doesn’t exist without causing a crash. You’ll get back nil if the dictionary doesn’t contain that key.
Looking closely at the result, you’ll see that the type is Int?. This indicates an optional integer which is a value that might be nothing — nil — and might be an integer. You’ll learn more about optionals in the next chapter.
Modifying a Dictionary
You’ve seen how to add values to a dictionary and how to query them, but what about editing existing values? You can overwrite them, using their key:
birdsSeen["Blue Jay"] = 2
print(birdsSeen)
That’s fine if you know the new value, but what if you want to edit the existing value? What happens if you see another robin?
birdsSeen["Robin"] += 1
This fails because Swift can’t be sure that there is a value for the key “Robin”. You’ll learn all about optionals and unwrapping later, so for now, accept that this can’t work.
But there’s a convenient way to tell a dictionary to use the value it has, or to use a default value if it doesn’t have one already:
birdsSeen["Robin", default: 0] += 1
birdsSeen["Penguin", default: 0] += 1
print(birdsSeen)
In this example, there was an existing value for “Robin” so Swift was able to increment it by one. There was no value for “Penguin” so Swift incremented the default value of zero.
The number of elements in a dictionary is accessible using the count property and you can remove an element by setting its value to nil:
birdsSeen.count
birdsSeen["Penguin"] = nil
print(birdsSeen)
birdsSeen.count
It did seem unlikely that you’d seen a penguin on your walk!
Now that you know about Swift’s data types, constants, variables and collections, you’re ready to jump back to Xcode in the next chapter.
Key Points
- The Swift REPL allows you to run Swift code in the Terminal. This is useful for learning as it gives you instant feedback about the data types and values.
- Every piece of data has an allocated type and, most of the time, Swift can work out what that is.
- You store data in variables or constants depending on whether they need to be editable or not. In computer terms, variables are mutable and constants are immutable.
- Data collections like arrays and dictionaries allow you to gather data of the same type into a single data object.
Where to Go From Here?
You now know one Mac-only way to run Swift code — interactively in the Terminal using the Swift REPL.
In the next chapter, you’ll expand on your knowledge as you learn a different way to run Swift, this time using Xcode.
For the official Swift information and guides, go to Swift.org.
To read about Swift in more depth, check out our Swift Apprentice: Fundamentals book.