Discover how @MainActor works


You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿


So you want to learn how @MainActor works in Swift but you don’t have a lot of time?

In just a few minutes we’ll go over everything you need to understand how this powerful feature works!

If you already have some experience working with iOS, you probably know this important rule: anything that is connected to the UI can only be accessed from the main thread.

This rule applies, of course, to UIKit objects, but also to SwiftUI’s property wrappers.

Ignore it and you’ll get a crash 💥

That’s when @MainActor comes into play!

This annotation will guarantee that a piece of code will run on the main thread.

@MainActor can be used in a variety of places: on types, on methods, on properties and even on closures.

And as soon as your code starts to handle something that’s been annotated with @MainActor, the compiler will make sure that the execution automatically switches to the main thread.

But be careful, because there’s a catch!

@MainActor will only have an effect in asynchronous code that uses Swift Concurrency.

If your code uses a completionHandler or Combine, then @MainActor will have no effect, and you will still need to manually switch the execution to the main thread.

That’s it, we’ve covered the basics of how @MainActor works in Swift 🥳

Thanks to this feature, we are able to guarantee that a piece of code will always run on the main thread, but only for code that uses Swift Concurrency 👌


You’ve enjoyed this article and you want to support my content creation?

You can leave me a tip ☺️ 👇

Buy Me A Coffee

Here’s the code it you want to experiment with it!

import Foundation

@MainActor
class ViewModel: ObservableObject {

    @Published var text = ""

    func updateText() {
        Task {
            let newText = await fetchFromNetwork()

            // guaranteed to run on the Main Thread
            text = newText
        }
    }
}

@MainActor
class ViewModel: ObservableObject {

    @Published var text = ""

    func updateText() {
        fetchFromNetwork { [weak self] newText in

            // ⚠️ @MainActor has no effect here
            self?.text = newText
        }
    }
}
Previous
Previous

Did you know Property Wrappers are great debugging tools? 🐛

Next
Next

I learned so much from these videos 😌