Exercise 3: Why ForEach Requires Identifiable or an Explicit id — Possible Solution ========================================================================================== ForEach's own real job is more than just looping over an array once to draw some initial views - it has to keep tracking each individual element across real, later data updates too, so that when the underlying array changes (an item added, removed, or reordered), SwiftUI can correctly figure out which on-screen row corresponds to which specific real data element, animate insertions/removals correctly, and avoid confusing one row's own identity with another's. Doing that correctly requires a real, STABLE way to identify each element - some value that reliably refers to "this particular real item," independent of its current position in the array (since position alone isn't reliable once items get inserted, removed, or reordered). The Identifiable protocol supplies exactly that: a real id property the type itself guarantees is present and stable. An explicit id: \.someProperty argument tells ForEach to use a specific existing property as that same kind of stable identifier instead, when the type doesn't conform to Identifiable directly. A plain struct with neither Identifiable conformance nor an explicit id: argument gives ForEach no real way to satisfy this requirement at all - there's no property SwiftUI could safely use as a stable identity, and rather than silently falling back to something unreliable (like array position, which would break the moment the data changes), Swift's own compiler catches this as a real error at compile time, since ForEach's own initializer's generic constraints simply aren't satisfied by a type offering no identifiable property whatsoever. ANSWER: ForEach needs a stable way to identify each element across data updates - not just for an initial render, but to correctly track insertions, removals, and reordering afterward. Identifiable supplies that via a guaranteed id property; an explicit id: argument supplies it via an existing property instead. A plain struct with neither satisfies neither of ForEach's own required initializer signatures, so the compiler rejects it at compile time rather than falling back to an unreliable identity source like array position. WHY THIS WORKS AS AN ANSWER ------------------------------ This explains the real underlying reason ForEach needs stable identity (tracking changes over time, not just an initial draw) rather than treating the Identifiable requirement as an arbitrary rule to memorize.