Bird
Raised Fist0
Swiftprogramming~20 mins

MainActor for UI work in Swift - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
MainActor Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this Swift code using @MainActor?
Consider this Swift code snippet using @MainActor to update UI state. What will be printed?
Swift
import Foundation

@MainActor
class ViewModel {
    var count = 0

    func increment() {
        count += 1
        print("Count is now \(count)")
    }
}

let vm = ViewModel()
Task {
    await vm.increment()
}
ACount is now 1
BCount is now 0
CCompilation error due to missing @MainActor on Task
DRuntime error due to accessing count off main thread
Attempts:
2 left
💡 Hint
Remember @MainActor ensures code runs on the main thread for UI safety.
🧠 Conceptual
intermediate
1:30remaining
Why use @MainActor for UI updates in Swift?
Which of these best explains why @MainActor is used for UI work in Swift concurrency?
AIt automatically updates UI elements without explicit calls.
BIt makes UI code run faster by using multiple threads.
CIt disables concurrency for UI code to simplify logic.
DIt guarantees UI code runs on the main thread to avoid race conditions and crashes.
Attempts:
2 left
💡 Hint
Think about thread safety and UI frameworks.
🔧 Debug
advanced
2:00remaining
What error occurs with this code missing @MainActor?
This Swift code updates UI state without @MainActor. What error will it cause?
Swift
class ViewModel {
    var text = ""

    func updateText() {
        text = "Hello"
        print(text)
    }
}

let vm = ViewModel()
Task {
    vm.updateText()
}
ANo error; code runs fine
BCompilation error: 'updateText' must be async
CRuntime warning about UI updates off main thread
DDeadlock because of missing await
Attempts:
2 left
💡 Hint
UI updates must happen on the main thread.
📝 Syntax
advanced
1:30remaining
Which option correctly applies @MainActor to a Swift function?
Choose the correct syntax to mark a Swift function to run on the main actor.
A@MainActor func updateUI() { print("UI updated") }
Bfunc @MainActor updateUI() { print("UI updated") }
Cfunc updateUI() { @MainActor print("UI updated") }
Dfunc updateUI() @MainActor { print("UI updated") }
Attempts:
2 left
💡 Hint
Attributes come before the function keyword.
🚀 Application
expert
2:30remaining
How many times is the UI updated in this Swift code?
Given this Swift code using @MainActor and async calls, how many times will the UI update print statement run?
Swift
import Foundation

@MainActor
class UIHandler {
    var updates = 0

    func updateUI() {
        updates += 1
        print("UI updated \(updates) times")
    }
}

let handler = UIHandler()

Task {
    await handler.updateUI()
    Task {
        await handler.updateUI()
    }
    await handler.updateUI()
}
A2 times
B3 times
C1 time
D4 times
Attempts:
2 left
💡 Hint
Count each awaited call to updateUI inside the tasks.

Practice

(1/5)
1. What is the main purpose of using @MainActor in Swift UI programming?
easy
A. To create multiple threads for UI tasks
B. To speed up background data processing
C. To disable asynchronous programming
D. To ensure UI updates run on the main thread safely

Solution

  1. Step 1: Understand the role of @MainActor

    @MainActor marks code to run on the main thread, which is required for UI updates to avoid crashes or glitches.
  2. Step 2: Compare options with this role

    Only To ensure UI updates run on the main thread safely correctly states that @MainActor ensures UI updates run safely on the main thread. Other options describe unrelated or incorrect behaviors.
  3. Final Answer:

    To ensure UI updates run on the main thread safely -> Option D
  4. Quick Check:

    @MainActor = safe UI updates on main thread [OK]
Hint: Remember: @MainActor means UI code runs on main thread [OK]
Common Mistakes:
  • Thinking @MainActor speeds up background tasks
  • Confusing @MainActor with creating multiple threads
  • Believing @MainActor disables async programming
2. Which of the following is the correct way to declare a function that updates UI and must run on the main thread using @MainActor?
easy
A. @MainActor async func updateUI() { /* code */ }
B. @MainActor func updateUI() { /* code */ }
C. func updateUI() async @MainActor { /* code */ }
D. func updateUI() @MainActor { /* code */ }

Solution

  1. Step 1: Recall correct syntax for @MainActor on functions

    The attribute @MainActor must appear before the 'func' keyword. Swift uses postfix 'async' after parameters for asynchronous functions: @MainActor func updateUI() async { /* code */ }. For synchronous UI updates, @MainActor func updateUI() { /* code */ } is correct.
  2. Step 2: Analyze each option

    @MainActor async func updateUI() { /* code */ } uses invalid prefix 'async func' syntax. @MainActor func updateUI() { /* code */ } is correct for synchronous UI function on main thread. func updateUI() async @MainActor { /* code */ } misplaces @MainActor after 'async'. func updateUI() @MainActor { /* code */ } places @MainActor incorrectly after function name.
  3. Final Answer:

    @MainActor func updateUI() { /* code */ } -> Option B
  4. Quick Check:

    @MainActor before func keyword = correct syntax [OK]
Hint: @MainActor before func keyword for main thread UI functions [OK]
Common Mistakes:
  • Using invalid prefix 'async func' syntax from other languages
  • Placing @MainActor after function name or 'async'
  • Misordering keywords in function declaration
3. Consider this Swift code snippet:
@MainActor
class ViewModel {
    var count = 0

    func increment() {
        count += 1
    }
}

let vm = ViewModel()
Task {
    await vm.increment()
    print(vm.count)
}
What will be printed when this code runs?
medium
A. 1
B. 0
C. Compilation error
D. Runtime crash

Solution

  1. Step 1: Understand @MainActor effect on ViewModel

    The class is marked @MainActor, so all its properties and methods are main actor-isolated and require 'await' when accessed from non-isolated contexts like Tasks.
  2. Step 2: Analyze the Task block

    The Task calls await vm.increment(), which correctly hops to the main actor and increments count to 1. The print(vm.count) is inside the Task closure, which is asynchronous and runs on the main actor context, so accessing vm.count is allowed and will print 1.
  3. Final Answer:

    1 -> Option A
  4. Quick Check:

    Accessing @MainActor properties inside async Task after await is allowed [OK]
Hint: Use 'await' for @MainActor-isolated properties in Tasks [OK]
Common Mistakes:
  • Thinking print(vm.count) works and shows 1 after await increment
  • Assuming count stays 0 without proper isolation handling
  • Expecting runtime crash instead of compilation error
4. Identify the error in this Swift code using @MainActor:
class DataFetcher {
    @MainActor
    func fetchData() async {
        // fetch data
    }
}

let fetcher = DataFetcher()
Task {
    await fetcher.fetchData()
}
medium
A. Cannot use @MainActor on a method inside a non-actor class
B. Missing async keyword on fetchData()
C. No error, code is correct
D. Must mark class as @MainActor, not just method

Solution

  1. Step 1: Check @MainActor usage on method

    Applying @MainActor to a method inside a normal class is allowed to ensure that method runs on main thread.
  2. Step 2: Verify async and call correctness

    The method is async and called with await inside a Task, which is correct usage.
  3. Final Answer:

    No error, code is correct -> Option C
  4. Quick Check:

    @MainActor on method in class is valid [OK]
Hint: You can mark methods @MainActor even in normal classes [OK]
Common Mistakes:
  • Thinking @MainActor only applies to classes
  • Forgetting async keyword on async methods
  • Assuming error without checking async/await usage
5. You have a SwiftUI app where a ViewModel class marked @MainActor updates a published property text. You want to fetch data asynchronously on a background thread and then update text safely on the main thread. Which approach correctly uses @MainActor to ensure safe UI updates?
hard
A. Mark the entire ViewModel as @MainActor and call async fetch on a background thread, then update text inside a @MainActor method
B. Do not use @MainActor; update text directly from any thread
C. Mark only the fetch method as @MainActor and update text without awaiting
D. Use DispatchQueue.global() to update text asynchronously

Solution

  1. Step 1: Understand thread safety for UI updates

    UI updates must happen on the main thread. Marking ViewModel as @MainActor ensures all its properties and methods run on main thread.
  2. Step 2: Use async fetch on background thread and update on main thread

    Fetching data can happen on background thread, but updating text must be done inside a @MainActor context, which is guaranteed if ViewModel is @MainActor.
  3. Final Answer:

    Mark the entire ViewModel as @MainActor and call async fetch on a background thread, then update text inside a @MainActor method -> Option A
  4. Quick Check:

    @MainActor ViewModel + async fetch + main thread update = safe UI [OK]
Hint: Mark ViewModel @MainActor to keep UI updates safe [OK]
Common Mistakes:
  • Updating UI from background thread without @MainActor
  • Not awaiting async fetch before updating UI
  • Using global queue to update UI causing crashes
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard