UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Difference between @MainActor and MainActor.run

Forums > SwiftUI

Hi, is there a difference between these two implementations? If there is, when should I be using one over the other?

  1. Updating published var using MainActor.runclass

    class Model1: ObservableObject {
    @Published var person: Person?
    
    // Initializing dummy networking class
    let service: Service
    init(service: Service) {
        self.service = service
    }
    
    // Update published variable in the main actor with MainActor.run
    func getPerson() async {
        let person = try! await service.downloadPerson()
        await MainActor.run(body: {
            self.person = person
        })
    }
    }
  2. Updating published var using @MainActor wrapper

    @MainActor class Model2: ObservableObject {
    @Published var person: Person?
    
    // Initializing dummy networking class
    let service: Service
    init(service: Service) {
        self.service = service
    }
    
    // No need to use MainActor.run since the class is wrapped with @MainActor
    func getPerson() async {
        let person = try! await service.downloadPerson()
        self.person = person
    }
    }
  • (dummy networking function that returns "Jake" in 1 second)
    // Dummy networking class
    class Service: ObservableObject {
    func downloadPerson() async throws -> Person {
        try await Task.sleep(nanoseconds: 1000000000)
        return Person(name: "Jake")
    }
    }
    // Dummy model
    struct Person {
    let name: String
    }

2      

First, class Service should not be an ObservableObject. It is not publishing any properties. Furthermore, unless it has instance properties not shown in your example, there is no reason to define it as a class, or even a struct.

Model1 is good: It calls downloadPerson() on a background thread and uses the main thread only to update the observed property person.

Model2 is bad because it calls downloadPerson() on the main thread. If you increase the sleep delay to a few seconds, you should see that it's blocking the user interface from accepting taps or typing.

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.