@MainActor in Swift explained with code examples Apple's Swift 6.2 introduces Default Actor Isolation in new Xcode 26 projects, automatically isolating app target code to the main actor, reducing the need for explicit @MainActor annotations. The @MainActor attribute, a global actor from the standard library, still functions identically, ensuring main-thread execution for properties, methods, instances, and closures, as explained by Antoine van der Lee in a SwiftLee article. @MainActor is a global actor that performs its tasks on the main thread. You can use it to dispatch to the main thread by marking properties, methods, instances, or closures with the attribute. Instead of manually dispatching using DispatchQueue.main.async , you let the compiler enforce main thread execution for you. If you’re new to Actors in Swift, I recommend reading my article Actors in Swift: how to use and prevent data races https://www.avanderlee.com/swift/actors/ first. The main actor behaves like other actors, with one important difference: it performs all its tasks on the main thread. Let AI Control the iOS Simulator https://www.rocketsim.app/blog/ai-agents-ios-simulator/?utm source=swiftlee&utm medium=owned ad&utm campaign=rocketsim ai simulator&utm content=sponsor block v1 RocketSim lets AI coding agents inspect, navigate, and verify your running iOS Simulator app through a CLI and Agent Skill for Cursor, Claude, Codex, and Xcode. Give agents real UI feedback instead of letting them guess from code alone. See how it works https://www.rocketsim.app/blog/ai-agents-ios-simulator/?utm source=swiftlee&utm medium=owned ad&utm campaign=rocketsim ai simulator&utm content=sponsor block v1 cta . What is a MainActor? A MainActor is a globally unique actor that performs its tasks on the main thread. You can use it for properties, methods, instances, and closures to perform tasks on the main thread. Proposal SE-0316 Global Actors https://github.com/apple/swift-evolution/blob/main/proposals/0316-global-actors.md introduced the main actor as an example of a global actor that inherits the GlobalActor protocol. Do you still need @MainActor in Swift 6.2 and later? Since Swift 6.2, your code might already run on the main actor without a single annotation. New projects in Xcode 26 and later enable Default Actor Isolation https://www.avanderlee.com/concurrency/default-actor-isolation-in-swift-6-2/ , which isolates all code inside your app target to the main actor unless you opt out. In other words: if you’re working inside a new project, you often don’t need to add @MainActor yourself anymore. This change is part of a bigger set of improvements that I’ve covered in Approachable Concurrency in Swift 6.2: A Clear Guide. For this article, it’s important to know that the attribute still works exactly the same. Whether you write @MainActor yourself or the compiler infers it, the same rules apply. MainActor: a Global Actor from the standard library The MainActor is a so-called global actor : an actor with a globally unique, shared instance. Its implementation is available by default and looks as follows: js @globalActor final actor MainActor: GlobalActor { static let shared: MainActor } Anywhere you use the @MainActor attribute, you’ll synchronize through this shared actor instance, ensuring mutually exclusive access to declarations. You can also define custom global actors, as I’ve explained in Global actor in Swift Concurrency explained with code examples https://www.avanderlee.com/concurrency/global-actor/ . How to use MainActor in Swift? You can use a global actor with properties, methods, closures, and instances. For example, we could add the @MainActor attribute to a view model to perform all tasks on the main thread: @MainActor final class HomeViewModel { // .. } Using nonisolated https://www.avanderlee.com/swift/nonisolated-isolated/ , we ensure methods without the main thread requirement perform as fast as possible by not waiting for the main thread to become available. You can only annotate a class with a global actor if it has no superclass, the superclass is annotated with the same global actor, or the superclass is NSObject. A subclass of a global-actor-annotated class must be isolated to the same global actor. In other cases, we might want to define individual properties with a global actor: js final class HomeViewModel { @MainActor var images: UIImage = } Marking the images property with the @MainActor property ensures that it can only be updated from the main thread: This is great when working with MVVM in SwiftUI https://www.avanderlee.com/swiftui/mvvm-architectural-coding-pattern-to-structure-views/ as you only want to trigger view redraws on the main thread. You can mark individual methods with the attribute as well: @MainActor func updateViews { /// Will always dispatch to the main thread as long as it's called /// within a concurrency context. } Be warned: this method is only guaranteed to run on the main thread when you call it from a concurrency context. The Swift 6 language mode catches most of these cases at compile time. I’ll dive deeper into this pitfall later in this article. And finally, you can mark closures to perform on the main thread: php func updateData completion: @MainActor @escaping - { Task { await someHeavyBackgroundOperation await completion } } Although in this case, you should rewrite the updateData method to an async variant without needing a completion closure. FREE 5-Day Email Course: The Swift Concurrency Playbook A FREE 5-day email course revealing the 5 biggest mistakes iOS developers make with with async/await that lead to App Store rejections And migration projects taking months instead of days even if you've been writing Swift for years Using the main actor directly The MainActor in Swift comes with an extension to use the actor directly: extension MainActor { /// Execute the given body closure on the main actor. public static func run