Main Thread Checker UI API called on a background thread -UIApplication applicationState
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
This warning means code touched a UI-related API from a background thread. In this specific case, UIApplication.shared.applicationState was read off the main thread, and Main Thread Checker is correctly warning that UIKit access must stay on the main queue.
Why applicationState Counts as UI API
Even though applicationState looks like a simple property read, it belongs to UIApplication, which is part of UIKit. UIKit is not thread-safe in the general sense expected by background worker code, so reads and writes that involve application state, view state, and other UI objects are supposed to happen on the main thread.
A common bad pattern looks like this:
This may appear harmless, but it violates the threading rules that Main Thread Checker is designed to catch.
Fix It by Hopping Back to the Main Queue
If a background task needs UI-related information, fetch that information on the main queue.
That is the simplest fix when the background work genuinely needs to consult UIKit before updating the UI or making a UI-dependent decision.
Better Design: Separate Background Logic From UI Logic
The stronger fix is often architectural rather than mechanical. Background work should usually produce data, not reach directly into UIKit. Then the UI layer can consume that data on the main thread.
This keeps UIKit access in the main-thread callback, where it belongs.
Use MainActor in Modern Swift When Appropriate
In newer Swift code, @MainActor can make UI-thread intent explicit.
If asynchronous code needs to call this from a concurrent context, Swift's actor isolation helps route the work back to the main actor correctly.
That does not replace understanding the thread model, but it does make the safe path easier to express.
Debug the Real Call Site, Not Just the Symptom
When Main Thread Checker fires, the important question is not only where the warning appeared, but why background code had access to UIKit at all.
Typical sources include:
- network completion handlers updating UI directly
- notification callbacks running on non-main queues
- custom operation queues touching UIKit
- reactive pipelines delivering values off the main thread
If you only wrap the one property read in DispatchQueue.main.async, the warning may go away while the broader design problem remains.
A Useful Rule of Thumb
Keep these boundaries clear:
- background queues do computation, I/O, and parsing
- the main queue reads or mutates UIKit state
- data crosses from background work to UI through an explicit handoff
Once the code is structured that way, Main Thread Checker warnings become much easier to understand and eliminate.
Common Pitfalls
The most common mistake is assuming that a read-only UIKit property is safe on any thread because no mutation occurs.
Another common issue is dispatching some UI updates to the main queue while leaving related UIKit reads on background queues. Developers also often treat the warning as a one-line fix instead of tracing the flow that allowed background code to depend on UI state in the first place.
Summary
- '
UIApplication.shared.applicationStateis a UIKit API and should be accessed on the main thread.' - Main Thread Checker is warning about a real threading violation.
- The immediate fix is to hop back to
DispatchQueue.mainbefore touching UIKit. - The better long-term fix is to separate background work from UI logic.
- In modern Swift,
@MainActorcan help make main-thread UI access explicit.

