App Architecture: MVVM & Why It Fits SwiftUI
iOS Development — Architecture & Data
Chapter 1 · App Architecture: MVVM & Why It Fits SwiftUI
Fundamentals' own capstone, TaskFlow, worked — but its TaskStore quietly did two genuinely
different jobs at once: holding raw task data, and deciding what a screen should display. This course
opens by giving that split a real name, MVVM, and a deliberate structure.
What MVVM Actually Is
MVVM — Model-View-ViewModel — is a real, well-established UI architecture pattern originally developed at Microsoft by architects Ken Cooper and Ted Peters, and publicly announced by fellow Microsoft architect John Gossman on his blog in 2005, as a variant of Martin Fowler's own earlier Presentation Model pattern.
Plain data — Task from Fundamentals, unchanged. No UI knowledge at all.
Holds state and logic for one screen — fetching, validating, transforming Models into what the View needs.
A real SwiftUI View — displays what the ViewModel exposes, forwards user actions back to it.
Why It Fits SwiftUI So Naturally
MVVM's own classic problem, in older UI frameworks, was wiring a View up to a ViewModel's changes by
hand. SwiftUI's real Observation framework (Fundamentals Chapter 6) removes that problem almost entirely
— an @Observable class is a real, natural ViewModel, and SwiftUI's own
view-diffing mechanism handles the "notify the View when something changes" job that MVVM traditionally
needed a separate binding system for.
| MVVM Role | Real SwiftUI Tool |
|---|---|
| Model | A plain struct — Identifiable/Codable as needed, no framework dependency |
| ViewModel | An @Observable class (iOS 17/Swift 5.9) — real, automatic change tracking, no manual @Published |
| View | A real SwiftUI View struct, holding its ViewModel via @State or receiving it via @Bindable |
Refactoring TaskFlow: A Real Before/After
Fundamentals' own TaskStore mixed a genuinely raw data array with screen-specific concerns —
nothing was wrong with it for a 10-chapter capstone, but it doesn't scale cleanly once a real app grows
past one screen's worth of logic.
The real MVVM version keeps Task itself as a pure Model, and gives the task-list screen its
own dedicated ViewModel — a real, meaningful rename, not just cosmetic, since it now explicitly owns
this screen's own logic rather than being a single, all-purpose store:
incompleteCount is a real, new computed property — exactly the kind of view-specific
derived state MVVM says belongs on the ViewModel, not scattered as ad hoc logic inside a View's own
body. And private(set) var tasks is a real, meaningful access restriction:
any View can read the task list, but only the ViewModel's own methods can change it —
genuinely enforced by the compiler, not just a convention.
The View itself barely changes — it still holds the object via @State/@Bindable
exactly as Fundamentals Chapter 6 covered — only the type name changes, reflecting what it now genuinely
represents:
body needs an if/switch to decide what data
to show (not just how to lay it out), that's a real, genuine sign the logic belongs on the ViewModel
instead — incompleteCount above is exactly that kind of decision, moved out of the View.
Hands-On Exercises
Add a real computed property highPriorityTasks: [Task] to TaskListViewModel, filtering tasks to only those with priority == 3, and use it in TaskListView to show a separate Section("High Priority") above the main task list.
Explain, in your own words, what real problem private(set) var tasks prevents that a plain var tasks would allow, and why that matters once an app has more than one View sharing the same ViewModel.
Explain, in your own words, why MVVM being a "community convention rather than an Apple mandate" is a genuinely important distinction to understand before adopting it in a real project, rather than treating it as a rule the compiler or SwiftUI itself enforces.
📄 View solutionChapter 1 Quick Reference
- MVVM: real 2005 Microsoft origin (Cooper, Peters, announced by Gossman), a variant of Fowler's Presentation Model — a community convention, not an Apple mandate
- Model = plain data, ViewModel = state/logic for one screen, View = a real SwiftUI
View @Observable(iOS 17/Swift 5.9) makes a plain class a natural, real ViewModel — no manual@Publishedwiring neededprivate(set) varis a real, compiler-enforced way to let Views read but not directly mutate ViewModel state- A rule of thumb: view-specific decision logic (filtering, computed summaries) belongs on the ViewModel, not inside a View's own
body