What is @MainActor
Tags: mainactor, swift
Published: 2024-04-11 08:33:40

---
title: What is @MainActor
published: true
date: 2024-03-10 15:20:05 UTC
tags: MainActor,Swift
canonical_url: https://wesleydegroot.nl/blog/@MainActor
---

In the ever-evolving world of Swift, concurrency has become a hot topic. With the introduction of Swift Concurrency, developers now have powerful tools at their disposal to write more efficient and responsive code. One such tool is the `@MainActor` attribute, which allows us to seamlessly execute code on the main queue.

## What is `@MainActor`?

`@MainActor` is a **global actor** that utilizes the main queue for executing its work. In practical terms, this means that methods or types marked with `@MainActor` can safely modify the UI because they will always run on the main queue. Additionally, calling `MainActor.run()` allows us to push custom work to the main actor, ensuring it executes on the main queue.

## Use Case: `@MainActor`

In the view model of a SwiftUI app, we often use `@Published` properties to update the UI. By marking the entire view model with `@MainActor`, we ensure that these UI updates always occur on the main queue. Here's an example:

```swift
@MainActor
class AccountViewModel: ObservableObject {
    @Published var username = "Anonymous"
    @Published var isAuthenticated = false
}
```

The view model is marked with `@MainActor`, ensuring that any UI updates triggered by `username` or `isAuthenticated` always occur on the main queue. This is particularly useful when working with SwiftUI, where UI updates must always occur on the main queue.

```swift
struct AccountView: View {
    @StateObject var viewModel = AccountViewModel()

    var body: some View {
        VStack {
            Text("Welcome, \(viewModel.username)!")
                .font(.title)
                .padding()

            Text(viewModel.isAuthenticated ? "You are logged in." : ("You are not logged in.")
                .font(.headline)
                .padding()
        }
    }
}
```

In this example, both `username` and `isAuthenticated` properties update the UI. By marking the entire class with `@MainActor`, we ensure that these UI updates always happen on the main actor. SwiftUI even takes care of this for us when we use `@StateObject` or `@ObservedObject` inside a view – the whole view runs on the main actor.

## Why Explicitly Use `@MainActor`?

You might wonder: if SwiftUI already ensures main-actor behavior, why bother adding `@MainActor` explicitly? Here are a few reasons:

1. **Beyond SwiftUI** : While SwiftUI handles main-actor behavior for observable objects, there are scenarios where our view models might be used outside of SwiftUI – perhaps in UIKit-based parts of our app or in more general Swift contexts. Explicitly marking them with `@MainActor` ensures consistent behavior across different contexts.

2. **Async/Await** : If our view models perform their own asynchronous work (e.g., downloading data from a server using async/await), `@MainActor` remains beneficial. It guarantees that UI updates always occur on the main actor.

3. **Opting Out** : If certain methods or computed properties should _not_ run on the main actor, we can use `nonisolated` – similar to how we do with regular actors.

## Global Actor Inference

Interestingly, any type containing properties of `@MainActor` objects also implicitly becomes `@MainActor` using global actor inference. Swift applies precise rules to ensure global-actor behavior works seamlessly without causing unnecessary hurdles.

In summary, `@MainActor` is a powerful tool for making UI updates safer and more predictable. Whether you're building SwiftUI views or working with UIKit, embracing `@MainActor` ensures your code dances gracefully on the main stage – the main queue.

Remember: **actors** are not suitable for observable objects; they must handle UI updates on the main actor. This is where `@MainActor` comes into play, ensuring that UI updates always occur on the main queue.

## Caveats

While `@MainActor` is a powerful tool, it's important to use it judiciously. Overusing `@MainActor` can lead to performance issues, as it forces all work to run on the main queue. Always consider whether a given piece of code truly needs to run on the main queue before marking it with `@MainActor`.

## Conclusion

Swift Concurrency has brought a new era of powerful tools to the Swift language. `@MainActor` is one such tool, allowing us to ensure that UI updates always occur on the main queue. By marking our types and methods with `@MainActor`, we can make our code safer and more predictable, ensuring that UI updates always occur on the main queue.

Resources:

[https://developer.apple.com/documentation/swift/mainactor](https://developer.apple.com/documentation/swift/mainactor)