Note Wisdom
These annotated notes cover Stanford CS193p Lecture 9 on Swift protocols, including Codebreaker bug fixes, elapsed‑time timer implementation, Equatable/Hashable/Identifiable, plus assignment tips and confusing points.
Institution: Stanford
Original Course: Stanford CS193p: iOS Development with SwiftUI | 2025 | L9: Protocols
Instructor Bio: This lecture is delivered by Paul Hegarty, Lecturer in Computer Science at Stanford University and the principal instructor of CS 193P since 2010. Paul Hegarty is a veteran software engineer and educator with deep roots in the Apple developer ecosystem. Earlier in his career he worked at NeXT Computer, where he contributed to the Objective-C language and the foundational tools that would eventually become Apple's modern development platform. He has taught iOS application development at Stanford for over fifteen years, guiding thousands of students through the transition from earlier UIKit frameworks to the modern SwiftUI declarative paradigm. He is widely recognized for his methodical teaching style, his emphasis on clean architectural patterns such as MVVM, and his ability to explain complex systems concepts through hands-on, live-coding demonstrations.
Course Description: This lecture covers protocols, one of Swift's most powerful and pervasive language features. It explains how protocols define blueprints of methods, properties, and initializers that types can adopt, and how protocol-oriented programming enables flexible, composable code design. The lecture also covers protocol extensions, protocol inheritance, and associated types, and demonstrates how protocols are used throughout SwiftUI — from the View protocol itself to Identifiable, Equatable, and Hashable. It also introduces elapsed time tracking as a practical application of these concepts in the CodeBreaker app.
restarting state variable. You only set restarting = true when the game has actually ended. If players restart an unfinished game, you never activate that state variable at all. This meant they could even delete some of the offset/slide‑down animation logic entirely, since the conditional state prevented conflicting view updates. Even though the slide‑down visual was optional, the lecturer noted you could keep it if you liked the aesthetic.width and height parameters on the frame modifier. Hard‑coding fixed dimensions will break your app on different hardware, especially iPad, which is a requirement for Assignment four. Your UI should adapt and stretch to fill whatever screen real estate it gets.aspectRatio. Hidden spacer‑style views that consume layout space are another workaround. The lecturer mentioned GeometryReader exists, but asked students to avoid it for assignments. They wanted learners to practice adaptive layout fundamentals first, even though GeometryReader could technically solve sizing problems.startTime of type Date marks when the game begins, and an optional endTime. The endTime is optional because when a game is running, the ending timestamp does not exist yet.endTime = Date.now. Every time the user restarts the game, reset startTime to the current moment and set endTime back to nil.ElapsedTime SwiftUI view. This view takes two inputs: a non‑optional start Date, and an optional end Date. Inside the view body they use if‑let optional unwrapping on endTime. If endTime has a value, format the time offset between start and end. If endTime remains nil, calculate the offset from start time against the current moment.Date.now directly inside the view body does not create a live‑updating timer. Date.now evaluates once when SwiftUI recomputes body. The view will not refresh repeatedly just because wall‑clock time passes. The lecturer introduced a special time data source that tells the Text view to continuously refresh its displayed offset value, making the counter tick live while the game is active.monospaced() to stop numbers from shifting width as digits change. Without monospaced fonts, different numeral widths cause the whole text block to jitter as seconds tick by. A lineLimit(1) keeps the formatted time string from wrapping onto multiple lines. The lecturer commented out this finished timer for the rest of their demo to avoid visual clutter.get or get set access requirements. Functions in a protocol list names, parameters and return types, no function bodies.
All contents below are exclusive to the paid Word file, NOT available on this web page
.font(), .padding() and many others.some and any. some hides a concrete type from one side of the code, but the compiler still knows the exact underlying type at compile time. var body: some View is the most common example. The caller only knows it is some View; Swift knows exactly which view type is returned.any erases type information completely. Resolution happens at runtime through boxing. It has performance overhead. The lecturer strongly discouraged students from reaching for any casually. For class assignments, they joked you should ask permission before you use any. SwiftUI’s ViewBuilder avoids any View entirely, by building strongly‑typed view tuples for you.== operator. The double‑equals operator is not baked into Swift language syntax. It is just a static function defined by the Equatable protocol. Many types get automatic synthesis of Equatable. For structs, all stored properties must themselves be Equatable. For enums without associated values you get conformance for free. Enums with associated data get synthesized implementation only if every piece of associated data conforms.== function when synthesis won’t work. The lecturer gave an important word of warning. SwiftUI uses Equatable to decide whether state has changed, to avoid unnecessary view body recomputation. If you write a custom Equatable conformance, your equality logic must truly represent whether your model instance is fully identical. If you ignore some properties in your equality check, SwiftUI will miss legitimate state changes. The lecturer also noted you should not blindly make every model struct Equatable. SwiftUI can detect mutations on value types through mutating functions even without Equatable.hash(into:) feeding your relevant properties into the hasher object. Like Equatable, Hashable synthesis works for structs and enums when all stored properties conform to Hashable. The lecturer touched briefly on inout parameters here, noting students would rarely need to write them.ForEach. ForEach needs stable, unique, hashable identifiers to match model data to on‑screen views. This keeps animations working when collections reorder, add or remove elements.id: argument at one of your struct’s properties. Or make your type conform to Identifiable, which requires an id property. The associatedtype ID inside Identifiable lets your id property be any Hashable type you choose.@Observable. Structs are value types; classes are reference types. SwiftUI does not use class inheritance much, but leverages reference semantics. The big catch: Swift cannot automatically detect when you mutate a class instance. To fix this, mark your model class with the @Observable macro. This macro generates hidden boilerplate so SwiftUI can observe changes to class properties and refresh the UI.some and any hard to fully grasp just from this verbal explanation. The lecturer explained compile‑time versus runtime type resolution, but there were no concrete side‑by‑side code snippets shown during the lecture. It is easy to intellectually know any carries runtime overhead, but less clear exactly what scenarios would push you to pick any even with that cost. The lecturer mostly just told students avoid it, without walking through a valid use‑case example. It would help to see small code samples contrasting both keywords.@Observable. Many ideas shown in the coming demos will also be useful for finishing Assignment three.Skip hours of watching lectures. Get organized notes, exam prep materials and problem solutions all in one Word file.
Click to see everything included
All contents below are exclusive to the paid Word file, NOT available on this web page

