This SwiftUI app shows a message and a button. When you tap the button, it waits 1 second and updates the message safely on the main thread using @MainActor.
iOS Swift
import SwiftUI
@MainActor
class ViewModel: ObservableObject {
@Published var message = "Loading..."
func loadData() async {
// Simulate background work
try? await Task.sleep(nanoseconds: 1_000_000_000)
message = "Data loaded!"
}
}
struct ContentView: View {
@StateObject private var vm = ViewModel()
var body: some View {
VStack {
Text(vm.message)
.padding()
Button("Load Data") {
Task {
await vm.loadData()
}
}
}
}
}
OutputSuccess
Important Notes
Always update UI on the main thread to avoid bugs.
@MainActor is an easy way to do this in Swift concurrency.
You can mark whole classes or individual functions with @MainActor.
Summary
MainActor ensures UI updates run on the main thread.
Use it when changing anything visible on screen.
It helps keep your app smooth and crash-free.
Practice
(1/5)
1. What is the main purpose of using @MainActor in Swift UI code?
easy
A. To ensure UI updates happen on the main thread
B. To run background tasks faster
C. To prevent memory leaks
D. To encrypt user data
Solution
Step 1: Understand UI thread requirements
UI updates must happen on the main thread to avoid crashes and keep the app smooth.
Step 2: Role of @MainActor
@MainActor ensures the annotated code runs on the main thread, making UI updates safe.
Final Answer:
To ensure UI updates happen on the main thread -> Option A
Quick Check:
MainActor = UI updates on main thread [OK]
Hint: MainActor always means UI code runs on main thread [OK]
Common Mistakes:
Thinking @MainActor speeds up background tasks
Confusing @MainActor with memory management
Assuming @MainActor encrypts data
2. Which of the following is the correct way to declare a function that updates UI using MainActor in Swift?
easy
A. func updateUI() { @MainActor /* code */ }
B. func updateUI() @MainActor { /* code */ }
C. func @MainActor updateUI() { /* code */ }
D. @MainActor func updateUI() { /* code */ }
Solution
Step 1: Recall correct syntax for @MainActor
@MainActor is an attribute placed before the function declaration.
Step 2: Check each option
@MainActor func updateUI() { /* code */ } correctly places @MainActor before the function name.
@MainActor
class ViewModel {
var count = 0
func increment() {
count += 1
}
}
let vm = ViewModel()
Task {
await vm.increment()
print(vm.count)
}
What will be printed?
medium
A. Compilation error
B. 0
C. 1
D. Runtime crash
Solution
Step 1: Understand @MainActor on class
The class ViewModel is marked @MainActor, so its methods and properties are isolated to the main actor.
Step 2: Analyze the code
await vm.increment() correctly increments count. Accessing vm.count inside the Task closure is safe because it's running on the main actor context.
Final Answer:
1 -> Option C
Quick Check:
Accessing @MainActor properties within the actor context is allowed [OK]
Hint: @MainActor properties can be accessed safely within actor context without await [OK]
Common Mistakes:
Thinking it prints 1 and forgetting await on print(vm.count)
Expecting runtime crash instead of compile error
Believing count stays 0 due to async context
4. You have this Swift function:
func updateLabel() {
label.text = "Hello"
}
When called from a background thread, the app crashes. How can you fix it using MainActor?
medium
A. Add @MainActor before the function declaration
B. Call updateLabel() inside DispatchQueue.global()
C. Remove the function and update label directly
D. Wrap label update inside DispatchQueue.main.async without @MainActor
Solution
Step 1: Identify cause of crash
UI updates must happen on main thread; background thread causes crash.
Step 2: Use @MainActor to fix
Adding @MainActor before function ensures it runs on main thread, preventing crash.
Final Answer:
Add @MainActor before the function declaration -> Option A
Quick Check:
@MainActor fixes UI thread crash [OK]
Hint: Use @MainActor to run UI code on main thread automatically [OK]
Common Mistakes:
Using global queue instead of main queue
Updating UI directly from background thread
Ignoring thread safety causing crashes
5. You want to update a SwiftUI view's text label from a background task safely. Which approach correctly uses @MainActor and async/await to update the UI?
hard
A. Use DispatchQueue.global().async to update the label
B. Declare the update function with @MainActor and call it with await inside the background task
C. Call the update function directly from the background thread without @MainActor
D. Update the label inside the background task without any special handling
Solution
Step 1: Understand UI update rules
UI updates must happen on main thread to avoid crashes and glitches.
Step 2: Use @MainActor with async/await
Marking the update function with @MainActor ensures it runs on main thread. Calling it with await from background task switches context safely.
Step 3: Evaluate other options
Options A, B, and D update UI from background thread causing errors or crashes.
Final Answer:
Declare the update function with @MainActor and call it with await inside the background task -> Option B
Quick Check:
@MainActor + await = safe UI update [OK]
Hint: Use @MainActor function called with await for UI updates [OK]
Common Mistakes:
Updating UI directly from background thread
Ignoring await when calling @MainActor function
Using global queue for UI updates
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.