Marshal iOS appIcon read to main thread to fix first-render tint race#192
Merged
NghiaTranUIT merged 1 commit intoMay 28, 2026
Merged
Conversation
`UIImage(named:)` is documented thread-safe, but during a SwiftUI app's first UIWindow tintColor resolution it races with UIKit's AccentColor asset lookup. When `ConnectionPackage` is constructed on the transporter queue (after the Proxyman connection becomes ready) and reaches the iOS branch of `Image.appIcon`, that off-main `UIImage(named:)` corrupts the window's inherited tintColor, baking iOS system blue into every descendant of the initial render. Mirror the existing OSX branch's `DispatchQueue.main.sync` hop so the iOS / tvOS / visionOS branch also resolves the icon on the main thread. Repro + before/after screenshots in the PR description.
NghiaTranUIT
approved these changes
May 28, 2026
NghiaTranUIT
left a comment
Member
There was a problem hiding this comment.
Thanks so much for your contribution 👍
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On iOS / tvOS / visionOS,
Image.appIconinSources/Packages.swiftcallsUIImage(named:)directly.ConnectionPackage(config:)is constructed on the transporter queue once the Proxyman connection becomes.ready, so that call ends up running on a background thread.During a SwiftUI app's first
UIWindowautomatic tintColor resolution, an off-mainUIImage(named:)races with UIKit's own AccentColor asset lookup. The race leaves the window's inheritedtintColorat the iOS system blue default(0, 0.533, 1, 1), which then bakes intoUITransitionViewand every descendant of the initial render. Any SwiftUI view consuming.tint(Image(systemName:).foregroundStyle(.tint),.buttonStyle(.borderedProminent),.glassProminent, and so on) ends up rendering in system blue on first launch instead of the app's AccentColor.The bug only shows up when Proxyman is actually running, because the off-main read happens in the connection-ready callback. No connection, no callback, no race.
Fix
Mirror the
os(OSX)branch'sDispatchQueue.main.synchop on the iOS / tvOS / visionOS branch. The macOS branch already carries the comment "Must be called on the Main Thread / Otherwise, we get a UI Background Checker warnings". The iOS branch now does the same thing.+23/-7 in one file, no API change.
Before / after
Minimal SwiftUI app, AccentColor set to black (P3), heart icon uses
.foregroundStyle(.tint), button uses.borderedProminent. Between the two screenshots, the only thing that changes is whether an off-mainUIImage(named: "AppIcon60x60")runs duringApp.init(), which is whatConnectionPackage.initdoes today.UIImage(named:))Repro
Self-contained xcodegen project, no third-party deps, no Atlantis required. It exercises the UIKit race directly, so you can see the failure mode without needing Proxyman running.
TintRace.zip
Toggle
static let BUGinSources/TintRaceApp.swiftto flip between the broken (off-main) and correct (no off-main) patterns. I also verified this branch against a real app with Atlantis 1.35.0 and Proxyman running: tint stays correct.Underlying issue
This patch is a workaround for what looks like a UIKit thread-safety bug.
UIImage(named:)is documented thread-safe and returns a valid image, andUIColor(named: "AccentColor")from the main thread still returns the correct color, so the asset catalog itself is not the problem. The corruption is in the first-window automatic tintColor resolution, which gets thrown off by any concurrent off-main asset-catalog access during launch. I've filed FB[TODO] with Apple. Until UIKit fixes it, the safe pattern is "don't callUIImage(named:)off-main duringApp.init()", which is the same constraint the macOS branch was already documenting here.