Lesson 3 - More on the Swift type system: Data types
In the previous exercise, Solved tasks for Swift lessons 1-2, we've practiced our knowledge from previous lessons.
In today's Swift tutorial, we're going to look at them in more detail and explain how to use them correctly. Today is going to be more theoretical, and the next lesson will be very practical. At the end, we'll make a few simple examples.
Swift recognizes two kinds of datatypes, value and reference. We'll discuss the reference data types later.
Value data types
We can easily imagine a variable of the value data type. It can be, for example, a number or a character. The value is stored directly in memory and can be accessed directly from the program. Note how I've used the word "directly" so many times. In the lessons throughout this course, we'll mainly be working with these variables.
Whole-number data types
Let's look at the table of all of the built-in whole-number data types in
Swift. Notice the
Int type, which we already know.
|Int||-2 147 483 648 to 2 147 483 647||32 bits|
|UInt||0 to 4 294 967 295||32 bits|
Of course, you don't have to memorize all these types, you can use just
Int to store whole numbers.
You can find more information in the official documentation. See Help ->
Developer Documentation and check it out. Then it's just about searching. You
can easily get information about specific data types in the Quick Help inspector
in Xcode on the right. Just select text with e.g. the
Int type in
your code and click Structure Reference in the inspector.
U prefix in
UInt means that it doesn't allow to
store negative values and can therefore store a positive value twice as large.
These types are called unsigned, the classic ones are called
For decimal numbers, the situation is similar, we can only choose between two
data types. They differ in the range of values, and also in precision, i.e. in
the number of decimal places. The
Double datatype is twice as
Float, which you probably deduced from its name.
|Float||+-1.5 * 10−45 to +-3.4 * 1038||7 numbers|
|Double||+-5.0 * 10−324 to +-1.7 * 10308||15-16 number|
Due to the fact that decimal numbers are stored in your computer in a binary system, there is some precision loss. Although the deviation is almost negligible, if you're programming, e.g. a financial system, don't use these data types for storing money since it could lead to slight deviations.
When we want to assign a value to a
Float variable in source
code, we have to specify the type explicitly. We don't have to do this with
Double since it's the default decimal type:
let f : Float = 3.14 let d = 2.72
As the decimal separator in source code, we use dots, regardless of our macOS regional settings.
Other built-in data types
Let's look at the other data types that Swift offers:
|Character||U+0000 to U+ffff||16 bits|
|Decimal||+-1.0 * 10−28 to +-7.9 * 1028||28-29 numbers|
|Bool||True or False||8 bits|
Character represents one character, unlike
represents the entire string of
Characters. We declare characters
with quotation marks in Swift and it's necessary to declare the data type,
otherwise it'd be
let c : Character = "A"
Decimal type solves the problem of storing decimal numbers
in binary form, because it stores the number internally similarly as text. It's
therefore used for storing monetary values. For all other mathematical
operations with decimal numbers we use
. We have to specify the data type as well to declare `Decimal
let number : Decimal = 3.14159265358979323846
Variables of the
Bool type can contain only two values:
false. We'll use them when we get to
conditions. In a variable of the
Bool type, we can store either
false or a logical expression. Let's try a simple
let b = false let expression = 15 > 5 print(b) print(expression)
The program output:
We may enclose expressions in parentheses. That may be useful when we have
more of them. Notice that the expression is equal to
15 is in fact more than
5. Going from expressions to
conditions isn't a far stretch, but we'll go into them in the next lesson.
The data type that you will see on every corner. Represents a string of characters, just any text. It's a value type. We'll introduce the most important methods that are good to know or at least it's good to know they exist. Test these methods in the Command Line, not in Playground.
We can ask if a
String starts with, ends with or contains a
substring. A substring is a part of a
String. All of these methods
will take a substring as a parameter and return
false). We can't react to the output yet;
however, let's write the return values nonetheless:
let s = "Rhinopotamus" print(s.hasPreffix("rhin")) print(s.hasSuffix("tamus")) print(s.contains("pot")) print(s.contains("lol"))
The program output:
false true true false
We can see that everything works as expected. The first phrase failed, as expected, because the string actually starts with a capital letter.
Distinguishing between capital and lowercase letters is not always what we
want. We'll often need to ask about the presence of a substring in a
case-insensitive way. The situation can be solved using the
lowercased() methods which return the
string in uppercase, resp. lowercase. Let's make a more realistic example than
Rhinopotamus. The variable will contain a line from some configuration file,
which was written by the user. Since we can't rely on the user's input we'll try
to eliminate possible errors, here by ignoring letter cases.
var config = "Fullscreen shaDows autosave" config = config.lowercased() print("Will the game run in fullscreen?") print(config.contains("fullscreen")) print("Will shadows be turned on?") print(config.contains("shadows")) print("Will sound be turned off?") print(config.contains("nosound")) print("Would the player like to use autosave?") print(config.contains("autosave"))
The program output:
Will the game run in fullscreen? true Will shadows be turned on? true Will sound be turned off? false Would the player like to use autosave? true
We can see that we're able to detect the presence of particular words in a string. First, we convert the entire string to lowercase or uppercase, and then check the presence of the word in lowercase or uppercase, respectively. By the way, simple processing of configuration script may actually look like this.
Another issue that may arise with user inputs is accented characters. Swift,
fortunately, works fully in Unicode. Which means that diacritics can hardly
corrupt our code. Always consider that most the people around the world don't
speak English as their primary language, so your application should support
their regional characters if you want them to use it...which you should. Another
pitfall can be whitespace characters, which are not visible for users, but can
cause program errors. Generally, it's a good idea to trim any input from the
user. We are provided with the
trimmingCharacters(in: ) method to
which we specify what we want to trim. Because it's an enumeration, we can write
. and Xcode will suggest a large variety of options what to
trim. You'll most likely use the
removing all white characters and new-line characters around the string.
print("Enter a number:") let s = readLine()! print("Here's what you originally wrote: " + s) print("Your text after the trim function: " + s.trimmingCharacters(in: .whitespacesAndNewLines)) let a = Int(s)! print("I converted the text you entered to a number. Here it is: \(a)")
Probably the most important method on
String is a replacement of
its parts with another text. We enter two substrings as parameters, the first
one is the one want to be replaced and the second one will replace it. The
method returns a new
String in which the replacing occurred. When
the method doesn't find the substring, it returns the original string. Let's
let s = "Java is the best!" let replaced = s.replacingOccurrences(of: "Java", with: "Swift") print(replaced)
Swift is the best!
We've already mentioned the string interpolation. In Swift, if we want to
insert variables on specific positions in a string, we wrap them in
\() and write them directly into the string:
let a = 10 let b = 20 let c = a + b let s = "When we add $a and $b, we get $c"
The program's output:
When we add 10 and 20, we get 30
This is a very useful and easy way to build strings. If we want to print
numbers, we can't avoid it. For combining string variables with another strings,
we can use string concatenation (simply use
+ to merge them into a
The count property
The last but most important property (NOT a method) is
i.e. the total number of characters. It returns an integer that represents the
number of characters of the string. We don't use parentheses because properties
don't have parameters. It'd make more sense if it was named
but that's something we have to get used to.
print("Type in your name:") let name = readLine()! print("Your name is \(name.count) characters long.")
To pad a string means to add few characters to the String so it has the required length. It's often used to add spaces, but you can add any characters you wish. Some languages offer useful methods for padding from the left or right. Swift has only one and it requires a lot of parameters. We'll describe them in detail further in the course.
If some of the methods in this lesson don't work for you,
make sure you added
import Foundation to your file for importing
the basic Swift functionality.
There's still a lot to go over and lots of other data types that we haven't covered. Regardless, there is a time for everything.
In the following exercise, Solved tasks for Swift lesson 3, we're gonna practice our knowledge from previous lessons.