As for your question
What is the right way to use @MainActor in swiftUI
The Answer is
Correct Usage of @MainActor and MainActor.run
@MainActor
func getPendingTaskList() async {
// UI update
viewState = .shimmering
do {
// API call
let response = try await useCase.getPendingList(
responseType: [PendingTaskResponse].self
)
// UI update
setupDisplayModel(response)
viewState = .loaded
} catch(let error) {
// Handle error and update UI
debugPrint(error.localizedDescription)
viewState = .loaded
}
}
Why This Works:
The @MainActor annotation ensures that the entire function is executed on the main thread. No explicit await MainActor.run block is needed for the UI updates.
When to Use await MainActor.run
If you are in a context that is not already running on the main thread, and you need to perform UI updates, you can use await MainActor.run to switch to the main thread. For example:
func fetchData() async {
do {
let response = try await useCase.getPendingList(
responseType: [PendingTaskResponse].self
)
// Switch to the main thread for UI updates
await MainActor.run {
setupDisplayModel(response)
viewState = .loaded
}
} catch(let error) {
await MainActor.run {
debugPrint(error.localizedDescription)
viewState = .loaded
}
}
}
await MainActor.run Here?fetchData() is not annotated with @MainActor, so it executes on a background thread (e.g., where the API call happens). We use await MainActor.run to ensure that the UI updates happen on the main thread.@MainActor and MainActor.runUse @MainActor for Tasks Involving UI Updates:
Annotate a method with @MainActor if most of its operations involve updating the UI. This simplifies your code by eliminating the need for await MainActor.run calls within the method.
Use await MainActor.run Only When Necessary:
If you're in a background thread (e.g., during a long-running task or API call) and need to perform UI updates, use await MainActor.run. Avoid using it unnecessarily within @MainActor-scoped methods.
Keep UI Updates Minimal:
Minimize the amount of work that is performed under @MainActor or MainActor.run to avoid blocking the main thread.
And you also refer this link about the Actor and MainActor
https://www.avanderlee.com/swift/mainactor-dispatch-main-thread/