Leave a rating/review
Notes: 05. Data & Data Types
Apple’s documentation on Numbers, Data, and Basic Values
This course was originally recorded in April 2020. It has been reviewed and all content and materials updated as of November 2021.
In this video you’ll learn more about Swift data types, how to view the type of a variable or object you have, and how each data type uses different amounts of bytes in memory or on disk.
Talking about data can get a little confusing, because the term is overloaded. In Swift, you use the Foundation type with the name Data. But the bytes it uses, themselves, can be considered “data” in general computer science terms. In modern computer architectures, the smallest unit of data you can address is a byte, which comprises 8 bits.
Swift has different types depending on the amount, and type, of data you need. This video’s start playground has some variables, grouped in sections, to give an example of some of the different data types available to you in Swift.
There are Integers, for whole numbers, Floats and Doubles, for decimal numbers, and an array of one of the available Integer types, to represent bytes.
Integers represent whole numbers, and these can be signed or unsigned, meaning they can be positive-only numbers, from zero upwards, or both positive and negative numbers.
Looking at the Integers section of your playground, under Data Types, you can see there are two constants: one for age and one for height. What differentiates them is that one is of type Int-8, or an 8-bit signed integer, while the other is of type U-Int-8, for an 8-bit unsigned, positive-only integer.
The UInt8 structure in Swift is also used to represent a byte, or 8 bits. With 8 bits, the range of values you’ve got available per-byte is two to the eighth power: which is 256. They start at zero, and go to two hundred fifty-five.
How can you tell the amount of bytes a data type uses, and what its maximum and minimum values are? Fortunately for you, Swift has got you covered.
You can use the MemoryLayout enumeration in order to find our the amount of bytes a data type uses on your specific hardware or device. Its size method let’s you pass in a variable or constant to get this.
MemoryLayout.size(ofValue: age)
The output in your sidebar should be 1, which is the correct number of bytes for an 8-bit unsigned integer. Alternatively, you can also get the number of bytes for a type itself, and not a variable or constant.
MemoryLayout<UInt8>.size
You should also see 1 in your sidebar as they are the same underlying data type. Integer structures also have handy variables that let you get the minimum and maximum values you can store in them.
UInt8.min
UInt8.max
The output is right in line with having two to the power of eight available for you. Given that it’s an unsigned integer, meaning you can’t store negative numbers, then the values you can store are from 0 to 255.
What about height? It will certainly differ somehow since it’s a signed integer.
MemoryLayout.size(ofValue: height)
Int8.min
Int8.max
The number of bytes it uses is still 1, which is correct given that you’re not using more bytes to store your data, only allowing for positive and negative numbers. What does change, however, is that your minimum value is -128, and then maximum is 127, still 256 possible values except they now have to account for both positive and negative numbers.
In addition to an 8-bit integer, or a byte of data, you also have at your disposal: Int, Int16, Int32, and Int64, along with their unsigned counterparts UInt, UInt16, UInt32m and UInt64. Of note, on 64-bit systems the amount of bytes that both Int and Int64 use is the same; it’s 8 bytes or, insert drumroll here, 64 bits!
Floating points, represented by the Float type in Swift for single-precision floating point values, allow you to store numeric values with decimals in them. As with Integers, they do have a limit on both the positive and negative end, and, unlike Integers, you do not have multiple variants of Float. Just Float.
You can see the amount of bytes a Float uses, as well as approximate minimum and maximum values it can hold.
MemoryLayout.size(ofValue: weight)
Float.leastNormalMagnitude
Float.greatestFiniteMagnitude
Floats use 4 bytes, and the values it can hold are large enough that you need to use exponentials to represent them. I said approximate values because the smaller or larger a floating point gets, the more precision you lose. The precision depends on what underlying format is used to represent floating-point values. Most computers and devices use a standard format known as the IEEE floating-point format.
Which brings us to Double, or double-precision floating point values. They too allow you to store decimal numbers, just much larger, or smaller, values, and, thus, with more precision. Doubles are not really twice as precise as Floats, it just derives from the fact that a double-precision number uses twice the bits as a regular, single-precision number.
You can check out the number of bytes a Double uses just as you did for Float.
MemoryLayout.size(ofValue: earthRadius)
Double.leastNormalMagnitude
Double.greatestFiniteMagnitude
As expected, Doubles use 8 bytes of memory, and have larger and smaller, possible values.
You won’t normally need to directly type out the numerical values of Data, but you should be familiar with what that would look like in order to have a better understanding of the mechanics of saving.
By default, when you use an integer literal in Swift, it’s in base 10: a “decimal” number. So, you can directly use zero to two-fifty-five. But you can prefix your integers as well to change their base.
If you use the 0b prefix, you’re working with a base 2 literal. The “b” is for “binary”, which only uses zero and one for digits. In decimal, we need three digits to express the full range of a byte. But in binary, we need 8, so it’s easier read if you split the number up with an underscore every four bits.
A groups of four bits is known as a “nybble”, and it’s often represented using a base 16; also known as “hexadecimal”, or just “hex” digit. Every nybble, in decimal, is a value between zero and fifteen, inclusive. Past the number 9, we use the first six letters of the alphabet, for hex literals. And the prefix, for “hex”, is zero “X”.
In your playground you will notice some examples of both positive and negativer integers, represented in binary or hexadecimal bases. They use the same amount of bytes, all you’re changing is how you represent the numbers themselves. Nothing more.
The favoriteBytes array contains some examples of regular decimal, binary, and hexadecimal representations of integer numbers. Together they make up bytes of data.
As with the other data types, you can see how much memory it occupies. The difference is that you can’t just rely on the size method in MemoryLayout because, as the documentation states, The result does not include any dynamically allocated or out of line storage. But try the following so you’re able to still see how much total memory it will use.
MemoryLayout<UInt8>.size * favoriteBytes.count
The result, as you might have guessed, is 16 bytes, an accurate number considering you have an array of sixteen UInt8 values, each using up one byte of memory.
As you’ve seen, Swift has many different Types to help you represent your data, and together they open up a world of possibilities. Even though today’s devices have quite a bit of RAM and drive memory, you should still try to use the appropriate data type depending on your needs.
In the next video you’ll take your favorite bytes and store them as Data in your playground’s document directory. See ya there!