Recap
Early on in this course we learned about variables and constants, each of which can hold a single value of a given data type:
var score = 0 // variable, data type is Int
let acceleration = 9.8 // constant, data type is Double
Structures allow us to describe more interesting data by grouping related individual variables and constants:
struct TradingCard {
let imageName: String
let playerName: String
let homeRunCount: String
let runsBattedIn: String
let average: String
let famousPlay: String
}
We can then create as many instances of a structure as needed:
let kellyGruber = TradingCard(imageName: "KellyGruber",
playerName: "Kelly Gruber",
homeRunCount: "117",
runsBattedIn: "443",
average: ".259",
famousPlay: "On April 16, 1989, Gruber was the first Blue Jay in history to hit for the cycle when he got four hits in six at–bats with six RBI and four runs scored. His cycle occurred in the following order: home run, double, triple, and single.")
let joeCarter = TradingCard(imageName: "JoeCarter",
playerName: "Joe Carter",
homeRunCount: "396",
runsBattedIn: "1445",
average: ".259",
famousPlay: "In 1993, in the World Series, with the Blue Jays leading three games to two, Carter came to bat with one out in the bottom of the ninth inning with the Blue Jays trailing 6–5 and Rickey Henderson and Paul Molitor on base. On a 2–2 count, Carter hit a three-run walk-off home run off Phillies pitcher Mitch Williams.")
This in turn allowed us to apply abstraction in the Trading Cards task.
We presented five different trading cards using just one structure that describes the data – TradingCard
:
And one structure to describe the user interface – DetailView
:
NOTE
Some students will have used helper views to shorten or divide up the code within
DetailView
.
The ability to navigate to the five different cards is provided by the PlayerListView
structure:
However, you may have been wondering – aren’t we supposed to avoid repeating ourselves?
Recall:
D.R.Y. Don’t Repeat Yourself!
Look at the code in the final screenshot above, of PlayerListView
.
It sure looks like we are repeating ourselves – five navigation links – otherwise identical, except for what player card they lead to.
The solution to this repetition is another way to store values – that is something called an array or list.
What is an array?
Variables and constants store a single value inside them.
An array is another programming language abstraction that lets us store many values at once.
We can then refer to those values using just one label, or name.
For example, here is an array that stores some of the house names here at Lakefield College School:
let houseNames = ["Matthews", "Uplands", "Cooper", "Moodie"]
If we used individual constants to store those values, we’d have to do something like this:
let firstHouse = "Matthews"
let secondHouse = "Uplands"
let thirdHouse = "Cooper"
let fourthHouse = "Moodie"
As you will soon learn, putting many instances of data into an array is far more flexible and helps us to manage complexity in our apps.
Terminology
Let’s take a brief detour to address terminology.
The word array means the same thing as list.
When referring to a programming language abstraction that holds multiple values – most documentation and tutorials you will find online will use the term array.
All AP materials from the College Board – including questions on the Computer Science Principles exam – use the term list.
These are the same thing.
Finally, note that an array or list is not quite the same thing as the List
structure in the SwiftUI framework.
An array, or list, in programming language terms lets us store many values but access them via one name.
A List
structure in SwiftUI lets use present many values in a user interface, like we did with the PlayerListView
structure:
In this course, you will hear and use both words:
- array
- list
That way, you will be able to understand tutorials you find online, and be prepared for the AP CSP exam.
Essential knowledge
An array, or list, is an ordered sequence of elements.
For example:
let blackPinkBand = ["Jisoo", "Jennie", "Rosé", "Lisa"]
The blackPinkBand
list has four elements.
An element is an individual value in a list that will always be assigned a unique index.
In the Swift programming language and nearly every other programming language, a list is zero-based.
That means the first element of a list has an index of 0.
The second element of a list has an index of 1.
Overall the blackPinkBand
list is described this way:
Index | Element |
---|---|
0 | Jisoo |
1 | Jennie |
2 | Rosé |
3 | Lisa |
We can access individual elements of a list by their index.
For example, in a command-line app, we could print the third band member’s name using this code:
print(blackPinkBand[2])
In a command-line app, the output looks like this:
TIP
In a command-line app, Xcode tells us that the program ended normally, without any errors, by showing the output:
Program ended with exit code: 0
So, that will always appear when you run a command-line app. It is not an error but a success message. 🎉
If we try to access an element that does not exist:
print(blackPinkBand[4])
…our app will crash. This is known as an Index out of range error.
Remember, the list in this example has just four elements, which can be accessed using index values from 0 through 3:
Index | Element |
---|---|
0 | Jisoo |
1 | Jennie |
2 | Rosé |
3 | Lisa |
We “reached beyond the end of the list” when we tried to access a fifth element by using the index of 4:
print(blackPinkBand[4])
Exercise 1
EXERCISE
Create a new command-line macOS app named
TopTenList
and create a list that has ten elements.For example, you might create a list of ten cities that you would like to visit someday, or your ten favourite ice cream flavours.
Then print the first, fifth, and final element of each list, similar to what was shown above.
Finally, try printing the eleventh element of your list.
Of course, that does not exist, and your app will crash. It’s good to become familiar with common reasons why your app might crash. Going past the end of a list is a very common programming error.
Iterating over lists
Loops are a natural friend to lists.
We can iterate over the values of a list using a loop.
Here is a loop that simply counts from zero to three:
// Count from 0 to 3
for i in 0...3 {
print(i)
}
The output will be:
0
1
2
3
We could use a loop like that to iterate over the elements in the blackPinkBand
list, and print their names on the screen:
Here is that same code, with the results shown using an animation:
However, this is not the best way to use a loop with a list in Swift.
Manually specifying the range of elements to iterate over, via the indices, like this:
for i in 0...3 {
… is prone to error.
It’s very easy to make a mistake and go past the end of the array, by asking for an element using an index that does not exist:
Here is that same code, with the results shown as an animation:
TIP
“Index out of range” is one of the most common categories of programmer errors.
It is much better to use the following code:
// Print each band member's name
for bandMember in blackPinkBand {
print(bandMember)
}
With a loop like this, the Swift compiler automatically iterates the correct number of times – four, in this case – since blackPinkBand
contains four elements.
With each iteration of the loop, the value of bandMember
is changed to temporarily hold the current element of the list.
Even better: if we are deliberate in how we name a list, the Xcode editor’s autocomplete is very helpful – this feature exists because iterating over a list is a very common task when developing an app:
Exercise 2
EXERCISE
Extend your
TopTenList
command-line app.Referring to the examples in the section above, iterate over the values of your list and print them to the screen using two different approaches in code.
Iterating over lists with SwiftUI
As you know, SwiftUI has a List
structure.
We used it in our Trading Cards app:
However, it’s name – List
– is not an accident.
The List
structure is not an array, but it works with arrays.
As it turns out: we can take individual instances of a structure, and put them into an array.
This has been done below, on line 66:
By placing instances of a structure into an array (also known as a list, lowercase “l”), a very nice edit can be made to the PlayerListView
page:
Now, the List
structure on line 13 is accepting the array (or list) named allPlayers
.
The List
structure in SwiftUI iterates over the allPlayers
array, which contains:
Index | Element |
---|---|
0 | kellyGruber |
1 | joeCarter |
2 | patBorders |
3 | tonyFernandez |
4 | georgeBell |
With each iteration the next player in the array is temporarily inserted into currentPlayer
and then used to create a NavigationLink
.
In turn, that instance of currentPlayer
(which changes as the loop iterates) is passed along to the DetailView
to allow each card to be shown.
This is very much like what happened earlier in the example from the command line app:
Here, the loop on line 14 iterates over the array, and each band member’s name is printed to the screen on line 15.
There is one final change that must be made, however.
To use an instance of a structure with List
in SwiftUI, that instance must be uniquely identifiable.
When a structure is used with a List
, but each instance cannot be uniquely identified, this error will appear:
To fix this, we declare that our TradingCard
structure will conform to the Identifiable
protocol by making the change shown on line 10 – note that the old code is shown in dark grey, and the new code is shown in dark blue:
Finally, on line 12, we actually make instances of the TradingCard
structure uniquely identifiable by adding a stored property named id
and assigning it a default value of UUID()
, using the assignment operator, =
.
UUID
is short for “universally unique identifier”.
With those minor changes to TradingCard
, the List
structure back on the list view is now happy and shows each player in the allPlayers
array:
Exercise 3
EXERCISE
Return to your own Trading Cards app.
Make your structure conform to the
Identifiable
protocol as explained above.Add the instances of your structure to an array, like was shown with
allPlayers
above.Finally, in your app’s list view, change the code so that the
List
structure uses your new array.In this way, you can change the list view from having this many lines of code:
… to this many:
By doing this, you will have managed complexity in your app by using an array with a
List
structure to elminate some very repetitive code.