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.run
Use @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/