Exercise 3: @MainActor (Where Code Runs) vs. actor (Serializing Shared State) — Possible Solution ========================================================================================================= @MainActor is fundamentally about WHERE a piece of code executes - it guarantees that any code marked with it (a whole class, or an individual method) runs specifically on the main thread, the one real thread UIKit and SwiftUI require for any UI-touching work. It doesn't, by itself, introduce any new serialization mechanism beyond what the main thread already is - the main thread has always run one thing at a time by its own basic nature; @MainActor's real job is making sure your own code actually lands there rather than running somewhere else. A plain actor type, by contrast, is about serializing access to a PARTICULAR piece of shared mutable state, regardless of which specific thread that serialization happens to occur on under the hood. The whole real point of an ordinary actor (like this chapter's own RequestCounter, or Exercise 2's own DownloadTracker) is protecting one specific type's own internal data from being read and written unsafely by multiple concurrent callers - it has no inherent connection to the main thread specifically, and in fact usually doesn't run there at all. A typical SwiftUI ViewModel usually needs @MainActor rather than being declared as a plain, ordinary actor because its whole real job is exposing state that SwiftUI itself reads directly, synchronously, to draw the UI on the main thread - if that state lived inside an ordinary actor instead, every single read from a View's own body would require await, which SwiftUI's own real, synchronous body property can't accommodate at all. @MainActor gives a ViewModel real, guaranteed-safe main-thread execution for its own mutations, while still allowing its properties to be read directly and synchronously by SwiftUI's rendering code, exactly the balance a ViewModel actually needs. ANSWER: @MainActor guarantees code runs on the one specific main thread UI frameworks require, while an actor serializes access to a particular type's own shared state regardless of which thread that happens on. A typical ViewModel needs @MainActor specifically because SwiftUI reads its properties directly and synchronously to render the UI - something an ordinary actor's own await-gated access would make impossible, since SwiftUI's body can't itself be asynchronous. WHY THIS WORKS AS AN ANSWER ------------------------------ This correctly distinguishes @MainActor's thread-guarantee role from a plain actor's state-serialization role, and explains the concrete, practical reason a SwiftUI ViewModel specifically needs the former.