In this exercise you will examine a small SwiftUI app built using the MVVM design pattern:

Working with a partner:
- Read through the source code carefully.
- Download a copy of the project and try it out together.
- Then work together to respond to each question below on the paper provided.
- Finally, check your responses by expanding the example solutions provided.
Source Code
import Foundation
import Observation
import SwiftUI
// MODEL
struct ChemistryTerm: Identifiable {
// MARK: Stored properties
let id = UUID()
let term: String
let definition: String
var isRevealed: Bool = false
}
// VIEW MODEL
@Observable
class ChemistryTermViewModel {
// MARK: Stored properties
var terms: [ChemistryTerm] = [
ChemistryTerm(
term: "Atom",
definition: "The smallest unit of an element that retains its chemical properties."
),
ChemistryTerm(
term: "Isotope",
definition: "Atoms of the same element that have different numbers of neutrons."
),
ChemistryTerm(
term: "Mole",
definition: "An SI unit representing 6.022 × 10²³ particles of a substance."
),
ChemistryTerm(
term: "Electronegativity",
definition: "The tendency of an atom to attract shared electrons toward itself in a bond."
),
ChemistryTerm(
term: "Oxidation",
definition: "A process in which an atom or ion loses one or more electrons."
),
ChemistryTerm(
term: "Catalyst",
definition: "A substance that increases the rate of a reaction without being consumed."
),
ChemistryTerm(
term: "Enthalpy",
definition: "The total heat content of a system measured at constant pressure."
),
ChemistryTerm(
term: "Molarity",
definition: "A measure of concentration equal to moles of solute per litre of solution."
),
ChemistryTerm(
term: "Valence Electrons",
definition: "Electrons occupying the outermost energy level of an atom."
),
ChemistryTerm(
term: "Le Chatelier's Principle",
definition: "A system at equilibrium will shift to partially offset any stress applied to it."
),
]
// MARK: Functions
func reveal(termToReveal: ChemistryTerm) {
for index in terms.indices {
if terms[index].id == termToReveal.id {
if terms[index].isRevealed == false {
terms[index].isRevealed = true
} else {
terms[index].isRevealed = false
}
}
}
}
}
// VIEW
struct ContentView: View {
// MARK: Stored properties
@State var viewModel = ChemistryTermViewModel()
// MARK: Computed properties
var body: some View {
NavigationStack {
ScrollView {
VStack(spacing: 12) {
Text("Tap to toggle between each definition or term.")
.foregroundStyle(.secondary)
ForEach(viewModel.terms) { term in
Button {
viewModel.reveal(termToReveal: term)
} label: {
VStack(alignment: .leading, spacing: 6) {
if term.isRevealed {
Text(term.term)
.font(.headline)
.foregroundStyle(.white)
} else {
Text(term.definition)
.font(.subheadline)
.foregroundStyle(.white)
.multilineTextAlignment(.leading)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(term.isRevealed ? Color.green.mix(with: .black, by: 0.2) : Color.blue.mix(with: .black, by: 0.2))
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}
}
.padding()
}
.navigationTitle("Chemistry Review")
}
}
}
#Preview {
ContentView()
}Review Questions
Question 1
Describe the overall purpose of this program.
SOLUTION
This program helps students review Chemistry vocabulary. The app displays a list of definitions as buttons. Tapping a button reveals the corresponding term in its place; tapping again hides it. This lets a student read a definition, recall the term, and check their answer.
Question 2
Describe where input and output occur in the running of the program. Identify the specific line(s) of code responsible for each.
SOLUTION
Input occurs when the user taps a button. On line 93, the
Buttonaction block captures the tap; on line 94,viewModel.reveal(termToReveal: term)passes the selected term to the view model.Output occurs when each button displays either a definition or a term. The
if term.isRevealedcheck on line 97 decides what is shown: line 98 displaysText(term.term)whentrue, and line 102 displaysText(term.definition)whenfalse. Line 110 also switches the background colour between dark blue and dark green.
Question 3
Identify where data is first stored in an array. Reference the specific line(s) of code that accomplish this.
SOLUTION
Data is first stored in an array on line 21, where the
termsproperty is declared and immediately initialized. TenChemistryTerminstances are created inline, beginning on line 22 with the entry for “Atom” and ending on line 61 with the closing of the last entry.
Question 4
What is the name of the chosen array?
SOLUTION
terms
Question 5
Describe where the chosen array is used in the program — for example, where it is iterated over, where individual elements are accessed, or where existing data in the array is used to produce new data or drive behaviour.
SOLUTION
The array is used in two places. First,
ForEach(viewModel.terms)on line 92 iterates over the array to produce one button per term, readingdefinitionandisRevealedon lines 97–105 to decide what to display.Second, the
reveal(termToReveal:)function iterates overterms.indiceson line 66, compares each element’sidto the tapped term’sidon line 67, and togglesisRevealedon lines 68–72 when a match is found.
Question 6
What does the data stored in the array represent within the program? Describe the type of data stored and what role it plays.
SOLUTION
Each element is an instance of the
ChemistryTermstruct (lines 6–13), representing one Chemistry vocabulary item. Each instance holds three pieces of data: the term (String, line 10), the definition (String, line 11), and whether it is currently revealed (Bool, line 12). Together, the elements form the complete set of flashcard content shown to the user.
Question 7
Explain how the terms array manages complexity in this program. In your response, explain why the program could not be written — or how it would have to be written differently — if the array were not used.
SOLUTION
The
termsarray manages complexity by storing all ten Chemistry vocabulary items in a single named collection rather than as ten separate sets of variables. Without it, each term would need its own variables (term1,definition1,isRevealed1, and so on) — thirty variables in total.The view code depends on the array too. The
ForEachon line 92 iterates over the collection to produce buttons; without it, all ten buttons would have to be written out by hand, and any layout change repeated ten times. Theforloop on line 66 similarly relies onterms.indicesto find and toggle the right element — otherwise a separateif-statement would be needed per term. The array makes the program shorter, easier to read, and easier to maintain.
Question 8
Identify where a function is defined in the program. What is the function’s name? What is its return type, if any? What parameter(s) does it define, and how do they affect what happens inside the function?
SOLUTION
The function is defined on line 65. Its name is
reveal, and it has no explicit return type — it performs an action rather than returning a value, so its return type is implicitlyVoid.It defines one parameter:
termToRevealof typeChemistryTerm. This receives the specific term the user tapped, and itsidis used on line 67 to find the matching element in the array, determining which element has itsisRevealedproperty toggled.
Question 9
Where is this function called in the program?
SOLUTION
The function is called on line 94, inside the
Buttonaction block inContentView, asviewModel.reveal(termToReveal: term). Here,termis the specificChemistryTerminstance theForEachon line 92 is currently iterating over, sorevealis called once each time the user taps any button.
Question 10
What is the purpose of the reveal function, and how does it contribute to the overall functionality of the program?
SOLUTION
The
revealfunction locates a specificChemistryTermin thetermsarray by matching unique identifiers, then toggles that term’sisRevealedproperty.It connects user input to a data change. When the user taps a button, the view calls
reveal, the view model updates the array, and becausetermsis tracked via@Observable, SwiftUI automatically re-renders the affected button — switching between the definition on a blue background and the term on a green background.
Question 11
Explain in detailed steps how the reveal function uses sequence, selection, and/or iteration to accomplish its purpose. Your explanation should be detailed enough for someone else to reproduce the function.
SOLUTION
- (Sequence) The function receives
termToReveal, aChemistryTerm, as its parameter.- (Iteration) Line 66 begins a
forloop overterms.indices, visiting each index in order.- (Selection) Line 67’s outer
ifchecks whetherterms[index].id == termToReveal.id. Since eachChemistryTermhas a uniqueUUID, this istruefor exactly one element.- (Selection) When the outer condition is
true, the innerifon line 68 checks whetherterms[index].isRevealed == false.- (Sequence) If
true, line 69 setsterms[index].isRevealed = true.- (Sequence) If
false, theelsebranch on line 71 setsterms[index].isRevealed = false.- (Iteration continues) The loop does not exit early; it visits the remaining indices, but no further matches occur.
- (Sequence) Once every index has been visited, the function ends.
Question 12
Describe a scenario where two separate calls to the reveal function, at different points while the program is running, would result in different outcomes.
SOLUTION
Consider a user who taps the “Atom” button twice in a row.
On the first call, “Atom“‘s
isRevealedisfalse. The function finds the matching element, the innerifon line 68 istrue, and line 69 setsisRevealed = true. The button now shows “Atom” on a green background.On the second call,
isRevealedistrue. The innerifis nowfalse, so theelsebranch on line 71 setsisRevealed = false. The button returns to showing the definition on a blue background.
Question 13
Describe the condition tested by each of the two calls identified above.
SOLUTION
Both calls test the same outer condition on line 67:
terms[index].id == termToReveal.id. This istruefor the “Atom” element in both calls.The difference is in the inner condition on line 68,
terms[index].isRevealed == false. On the first call it istrue(so theifbranch runs); on the second it isfalse(so theelsebranch runs).
Question 14
What will the result of the first call be? What will the result of the second call be?
SOLUTION
After the first call, “Atom“‘s
isRevealedchanges fromfalsetotrue. SwiftUI detects the change and re-renders the button: the definition is replaced by “Atom” in a bold headline font, and the background changes from dark blue to dark green.After the second call,
isRevealedflips back tofalse. SwiftUI re-renders again: the term is replaced by the definition in a smaller subheadline font, and the background returns to dark blue — the button is back to its original state.