Issue Description I'm experiencing a bizarre SwiftUI state update issue that only occurs in Xcode development environment (both Canvas preview and device debugging), but does not occur in production builds downloaded from App Store.
Symptom:
-
User taps a button that modifies a @State variable inside a .sheet
-
Console logs confirm the state HAS changed
-
But the UI does not update to reflect the new state
-
Switching to another file in Xcode and back to ContentView instantly fixes the issue
-
The production build (same code) works perfectly fine
Environment
-
Xcode: 16F6 (17C52)
-
iOS: 26.2 (testing on iPhone 13)
-
macOS: 25.1.0 (Sequoia)
-
SwiftUI Target: iOS 15.6+
-
Issue: Present in both Xcode Canvas and on-device debugging
-
Production: Same code works correctly in App Store build (version 1.3.2)
Code Structure
Parent View (ContentView.swift)
struct ContentView: View { @State private var selectedSound: SoundTheme = .none @State private var showSoundSheet = false var body: some View { VStack { // Display button shows current selection SettingButton( title: "Background Sound", value: getLocalizedSoundName(selectedSound) // ← Not updating ) { showSoundSheet = true } } .sheet(isPresented: $showSoundSheet) { soundSelectionView } } private var soundSelectionView: some View { ForEach(SoundTheme.allCases) { sound in Button { selectedSound = sound // ← State DOES change (confirmed in console) // Audio starts playing correctly audioManager.startAmbientSound(sound) } label: { Text(sound.name) } } } private func getLocalizedSoundName(_ sound: SoundTheme) -> String { // Returns localized name return sound.localizedName }}
What I've Tried
Attempt 1: Adding .id() modifier SettingButton(...) .id(selectedSound) // Force re-render when state changes
Result: No effect
Attempt 2: Moving state modification outside withAnimation // Before (had animation wrapper):withAnimation { selectedSound = sound}// After (removed animation):selectedSound = sound
Result: No effect
Attempt 3: Adding debug print() statements selectedSound = soundprint("State changed: (selectedSound)") // ← Adding this line FIXES the issue!
Result: Mysteriously fixes the issue! But removing print() breaks it again. This suggests a timing/synchronization issue in Xcode's preview system. Observations
What works: ✅ Console logs confirm state changes correctly ✅ Switching files in Xcode triggers view reconstruction → everything works ✅ Production build from App Store works perfectly ✅ Adding print() statements "fixes" it (likely changes execution timing)
What doesn't work: ❌ Initial file load in Xcode ❌ Hot reload / incremental updates ❌ Both Canvas preview and on-device debugging
Workaround that works:
- Click another file in Xcode
- Click back to ContentView.swift
- Everything works normally
Key Question
Is this a known issue with Xcode 16's SwiftUI preview/hot reload system?
The fact that:
- Same exact code works in production
- Adding print() "fixes" it
- File switching triggers reconstruction that fixes it
...all suggest this is an Xcode tooling issue, not a code bug.
However, it makes development extremely difficult as I can't reliably test changes without constantly switching files or killing the app.
What I'm Looking For
- Confirmation: Is this a known Xcode 16 issue?
- Workaround: Any better solution than constantly switching files?
- Root cause: What's causing this state update timing issue?
Any insights would be greatly appreciated!