Using @MainActor on an ObservableObject or a method

In most WWDC videos where a data model/view model with ObservableObject is used, I see the model is marked with @MainActor attribute.
I wonder if it is the Apple recommended way of dealing with an observable data model object? :thinking: Links to official documents or videos would be appreciated.

Sometimes I need to hold other instances that don't need to be observable in the data model, i.e., they only need to be the "single source of truth" and not re-created through view state changes. In this case, I'd like to know if it is an acceptable practice to not mark the whole data model object as @MainActor, but only the UI-specific methods.

Also, if I do so with a more granular usage of main actor, does it bring any performance benefits?

Thanks!

// Using main actor on the whole class
@MainActor
private class Model: ObservableObject {
    /// Some other object that doesn't need to be observable.
    let storage = Storage()
    
    @Published private(set) var statusMessage: String = ""
    
    /// Some other methods that don't need to be on the main thread.
    func foo(_ bar: Int) {
        // do something on an arbitrary thread.
    }
    
    func setStatusMessage(_ message: String) {
        statusMessage = message
    }
}

// 🆚 using main actor only on the UI related methods

private class Model: ObservableObject {
    let storage = Storage()
    
    @Published private(set) var statusMessage: String = ""
    
    func foo(_ bar: Int) {}
    
    @MainActor
    func setStatusMessage(_ message: String) {
        statusMessage = message
    }
}

I am currently dabbling with this question. I found this article helpful.

1 Like

Here is another discussion I found on StackOverflow. While it has some useful info, there is still not a definitive answer on whether or not in most cases the data model should be marked with @MainActor.

Nonetheless, with the introduction of @Observable macro, I guess this question will gradually become irrelevant as people move to iOS 17.0+. :man_shrugging: