Hi,
I have created an AppIntent in which there is a parameter called price, I have set the default value as 0.
@Parameter(title: "Price", default: 0)
var price: Int
Problem
When the shortcut is run this parameter is skipped
Aim
I still want to price to be asked however it needs to be pre-filled with 0
Question
What should I do that the shortcut can still ask the price but be pre-filled with 0?
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Overview
I have a custom type Statistics that has 3 properties inside it
I am trying to return this as part of the AppIntent's perforrm method
struct Statistics {
var countA: Int
var countB: Int
var countC: Int
}
I would like to implement the AppIntent to return Statistics as follows:
func perform() async throws -> some IntentResult & ReturnsValue<Statistics> {
...
...
}
Problem
It doesn't make much sense to make Statistics as an AppEntity as this is only computed as a result.
Statistics doesn't exist as a persisted entity in the app.
Questions
How can I implement Statistics?
Does it have to be AppEntity (I am trying to avoid this)? (defaultQuery would never be used.)
What is the correct way tackle this?
Hello, the Liquid Glass effect of iOS 26 was possible during development, but it disappeared after its release and launch. I haven't found the reason for this, could you please help me clarify
Topic:
UI Frameworks
SubTopic:
UIKit
I am building a macOS utility using SwiftUI and Swift that records and displays keyboard shortcuts (like Cmd+C, Cmd+V) in the UI. To achieve this, I am using NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]).
I am aware that global monitoring usually requires the app to be non-sandboxed. However, I am seeing some behavior I don't quite understand during development:
I started with a fresh SwiftUI project and disabled the App Sandbox.
I requested Accessibility permissions using AXIsProcessTrustedWithOptions, manually enabled it in System Settings, and the global monitor worked perfectly.
I then re-enabled the App Sandbox in "Signing & Capabilities."
To my surprise, the app still records global events from other applications, even though the Sandbox is now active.
Is this expected behavior? Does macOS "remember" the trust because the Bundle ID was previously authorized while non-sandboxed, or is there a specific reason a Sandboxed app can still use addGlobalMonitor if the user has manually granted Accessibility access?
My app's core feature is displaying these shortcuts for the user's own reference (productivity tracking). If the user is the one explicitly granting permission via the Accessibility privacy pane, will Apple still reject the app for using global event monitors within a Sandboxed environment?
Code snippet of my monitor:
// This is still firing even after re-enabling Sandbox
eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]) { event in
print("Captured: \(event.charactersIgnoringModifiers ?? "")")
}
I've tried cleaning the build folder and restarting the app, removing the app from accessibility permission, but the events keep coming through. I want to make sure I'm not relying on a "development glitch" before I commit to the App Store path.
Here is the full code anyone can use to try this :-
import SwiftUI
import Cocoa
import Combine
struct ShortcutEvent: Identifiable {
let id = UUID()
let displayString: String
let timestamp: Date
}
class KeyboardManager: ObservableObject {
@Published var isCapturing = false
@Published var capturedShortcuts: [ShortcutEvent] = []
private var eventMonitor: Any?
// 1. Check & Request Permissions
func checkAccessibilityPermissions() -> Bool {
let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true]
let accessEnabled = AXIsProcessTrustedWithOptions(options)
return accessEnabled
}
// 2. Start Capture
func startCapture() {
guard checkAccessibilityPermissions() else {
print("Permission denied")
return
}
isCapturing = true
let mask: NSEvent.EventTypeMask = [.keyDown, .keyUp]
eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: mask) { [weak self] event in
self?.processEvent(event)
}
}
// 3. Stop Capture
func stopCapture() {
if let monitor = eventMonitor {
NSEvent.removeMonitor(monitor)
eventMonitor = nil
}
isCapturing = false
}
private func processEvent(_ event: NSEvent) {
// Only log keyDown to avoid double-counting the UI display
guard event.type == .keyDown else { return }
var modifiers: [String] = []
var symbols: [String] = []
// Map symbols for the UI
if event.modifierFlags.contains(.command) {
modifiers.append("command")
symbols.append("⌘")
}
if event.modifierFlags.contains(.shift) {
modifiers.append("shift")
symbols.append("⇧")
}
if event.modifierFlags.contains(.option) {
modifiers.append("option")
symbols.append("⌥")
}
if event.modifierFlags.contains(.control) {
modifiers.append("control")
symbols.append("⌃")
}
let key = event.charactersIgnoringModifiers?.uppercased() ?? ""
// Only display if a modifier is active (to capture "shortcuts" vs regular typing)
if !symbols.isEmpty && !key.isEmpty {
let shortcutString = "\(symbols.joined(separator: " ")) + \(key)"
DispatchQueue.main.async {
// Insert at the top so the newest shortcut is visible
self.capturedShortcuts.insert(ShortcutEvent(displayString: shortcutString, timestamp: Date()), at: 0)
}
}
}
}
PS :- I just did another test by creating a fresh new project with the default App Sandbox enabled, and tried and there also it worked!!
Can I consider this a go to for MacOs app store than?
I am porting my app to SwiftUI and I am hitting a wall when using ScrollView. In my application, I have nested scrollViews to represent a scheduler.
outer vertical scroll view
inner horizontal scroll view that allows to horizontally scroll multiple columns in the scheduler
each column in the inner scroll view is a view that needs to allow for a drag to initiate the creation of a new appointment
on macOS, I do a mouse-down drag, so it does not affect the scroll view and works fine
on iOS, if I add a drag gesture to the column, it short circuits the scroll view and scrolling becomes disabled. To initiate the drag, there is a long-press, and that gesture is fine, only the subsequent drag gesture is problematic.
I have attached URL to a test app. The UI allows you to toggle the drag gesture. Hopefully, someone can help to get it to work since I would eventually like to port the macOS target to Catalyst.
Download Test App
Topic:
UI Frameworks
SubTopic:
SwiftUI
I’m trying to understand how SwiftUI List handles row lifecycle and reuse during scrolling. I have a list with around 60 card views; on initial load, only about 7 rows are created, but after scrolling to the bottom all rows appear to be created, and when scrolling back to the top I again observe multiple updates and apparent re-creation of rows. I confirmed this behavior using Instruments by profiling my app. Even though each row has a stable identifier, the row views still seem to be destroyed and recreated, which doesn’t resemble UIKit’s cell reuse model. I’d like clarity on how List uses identifiers internally, what actually gets reused versus recreated, and how developers should reason about performance and view lifetime in this case.
I have a SwiftUI-based universal app which creates a file that it stores in documentsDirectory. On iOS/iPadOS, this file is stored in the application's Documents directory and is accessible via the Files app.
On MacCatalyst, this operation does the same thing — it creates the file and stores it in ~/Library/Containers/<app directory>/Data/Documents. However what I want is for the document to be stored in ~/Documents, so that it is easily accessible to the user.
How can I do that? I'd like it to occur without (for example) having to show a SaveFile panel...
So, I was going to make a macOS application that accepts dropped apps. This used to work fine in older macOS versions such as High Sierra. It also works for apps like Script Editor.
But I cannot get my own app, made with either Xcode or Script Editor, receive dropped apps any more.
Mind you, Finder does accept dropping .app items onto my app, so the CFBundleDocumentTypes are fine. And, as I said, it works in High Sierra.
The problem is that some part in AppKit or Core Services filters out apps from the list of dropped URLs before application:openURLs: is invoked.
What's up with that, and how do I make this work again?
I've tried copying all of Script Editor's Info.plist entries to no avail, so there's something more sinister going on here.
Also filed under FB21456137
Topic:
UI Frameworks
SubTopic:
AppKit
Hi!
On iOS 26, Apple’s Mail app shows an effect where a list row gets rounded corners while you’re swiping (so the row visually “matches” the rounded swipe buttons).
In my app I’m using SwiftUI List + .swipeActions. I also need a custom row tint (e.g. subtle red/gray highlight based on state). The problem is:
If I apply my tint using .background / .clipShape, it moves with the row content during swipe and looks wrong.
If I use .listRowBackground(...), I keep the tint, but I don’t get the same rounded-corners “morphing” effect as in Mail (or it looks inconsistent).
Question:
What’s the correct way in iOS 26 to keep a custom row tint and get the system-style rounded corners / liquid-glass effect while swiping?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I have an app that records a 32 x 32 rect under the cursor as the user moves it around and it sends it to Flutter.
It suffers from major lag.
Instead of getting 30 fps, I get about 7 fps. That is, there are significant lags between screen grabs.
This on an Intel Mac mini x64 with 15.7.3 and one display.
flutter: NATIVE: ExplodedView framesIn=2 timeSinceStart=1115.7ms gapSinceLastFrame=838.8ms
flutter: NATIVE: ExplodedView framesIn=4 timeSinceStart=1382.6ms gapSinceLastFrame=149.9ms
flutter: NATIVE: ExplodedView framesIn=5 timeSinceStart=1511.0ms gapSinceLastFrame=128.4ms
flutter: NATIVE: ExplodedView framesIn=7 timeSinceStart=1698.3ms gapSinceLastFrame=102.9ms
flutter: NATIVE: ExplodedView STOP polling totalTime=4482.6ms framesIn=28 framesSent=28 acks=28
Here's a testable excerpt:
import ScreenCaptureKit
import CoreMedia
import CoreVideo
import QuartzCore
final class Test: NSObject, SCStreamOutput, SCStreamDelegate {
private let q = DispatchQueue(label: "cap.q")
private var stream: SCStream?
private var lastFrameAt: CFTimeInterval = 0
private var frames = 0
func start() {
SCShareableContent.getExcludingDesktopWindows(false, onScreenWindowsOnly: true) { content, err in
guard err == nil, let display = content?.displays.first else {
print("shareableContent error: \(String(describing: err))"); return
}
let filter = SCContentFilter(display: display, excludingWindows: [])
let config = SCStreamConfiguration()
config.showsCursor = false
config.queueDepth = 1
config.minimumFrameInterval = CMTime(value: 1, timescale: 30)
config.pixelFormat = kCVPixelFormatType_32BGRA
config.width = 32
config.height = 32
config.sourceRect = CGRect(x: 100, y: 100, width: 32, height: 32)
let s = SCStream(filter: filter, configuration: config, delegate: self)
try! s.addStreamOutput(self, type: .screen, sampleHandlerQueue: self.q)
self.stream = s
s.startCapture { startErr in
print("startCapture err=\(String(describing: startErr))")
}
// Optional: move sourceRect at 30Hz (cursor-follow simulation)
Timer.scheduledTimer(withTimeInterval: 1.0/30.0, repeats: true) { _ in
let c2 = SCStreamConfiguration()
c2.showsCursor = false
c2.queueDepth = 1
c2.minimumFrameInterval = CMTime(value: 1, timescale: 30)
c2.pixelFormat = kCVPixelFormatType_32BGRA
c2.width = 32
c2.height = 32
let t = CACurrentMediaTime()
c2.sourceRect = CGRect(x: 100 + (sin(t) * 50), y: 100, width: 32, height: 32)
s.updateConfiguration(c2) { _ in }
}
}
}
func stream(_ stream: SCStream, didOutputSampleBuffer sb: CMSampleBuffer, of type: SCStreamOutputType) {
guard type == .screen else { return }
let now = CACurrentMediaTime()
let gapMs = (lastFrameAt == 0) ? 0 : (now - lastFrameAt) * 1000
lastFrameAt = now
frames += 1
if frames <= 10 || frames % 60 == 0 {
print("frames=\(frames) gapMs=\(String(format: "%.1f", gapMs))")
}
}
}
I started to use the Accessibility features of UIKit but cannot get the numbers or labels to show up on UICollectionCells. The image here shows a 3x3 matrix with no numbers, but the numbers on the menu commands show up.
Actually these are just iOS accessibility features, not my app.
I've tried reducing the size of my images or no images, but nothing shows up (in any of my UICollection code). I can get them to work on UITableView cells. I've tried the Accessibility selection in the storyboard or code, but nothing helps.
Problem
When a List / Form is added inside a TabView and navigationTitle is set, then switching between tabs causes the navigation title to flicker.
Feedback:
FB21436493
Environment
Xcode: 26.2 (17C52)
iOS: 26.2 (23C55)
Reproducible on: Both simulator and device
Root cause
When List / Form is commented out, issue doesn't occur
Steps to Reproduce
Run app on iOS
Switch between tabs
Notice that the navigation title flickers
Code
ContentView
import SwiftUI
struct ContentView: View {
@State private var selectedTab = TabItem.red
var body: some View {
NavigationStack {
TabView(selection: $selectedTab) {
ForEach(TabItem.allCases, id: \.self) { tab in
Tab(tab.rawValue, systemImage: tab.systemImageName , value: tab) {
// Problem occurs with a List / Form
// Commenting out list works without flickering title
List {
Text(tab.rawValue)
}
}
}
}
.navigationTitle(selectedTab.rawValue)
}
}
}
TabItem
enum TabItem: String, CaseIterable {
case red
case green
case blue
var systemImageName: String {
switch self {
case .red:
"car"
case .green:
"leaf"
case .blue:
"bus"
}
}
}
Screen recording:
Topic:
UI Frameworks
SubTopic:
SwiftUI
I am trying to set an image as the background in the window of a DMG. The image is: PNG file; 144x144 resolution; 1138x574 size.
In macOS Tahoe, the image is added by: selecting the DMG window; opening the "Show View Options" dialog; clicking on "Picture"; dragging the image file to the small square box labelled "Drag image here"; closing "Show View Options" dialog. The DMG is then ejected. In Disk Utility, the image file is converted to "Read Only image (UDRO)".
The converted image file is opened and the background image is visible. The image file is then copied to a MacBook running macOS 12 Monterey and opened. The background image is NOT shown. The image file is copied to a Mac mini running macOS 14 Sequoia and opened. The background image is NOT shown.
Have read past online discussions in which it was explained that an image file called "background" should be inside a hidden folder called ".background". The above procedure did not do that. Is that old advice still correct for macOS Tahoe ?
Has Tahoe somehow broken the method used for setting the background of a Window ?
Is the method used in Tahoe different to past versions of macOS ? If so, is there a way of maintaining compatibility with old versions of macOS ?
Is there any documentation on how to set the background image of a DMG window which might explain this behaviour ??
Thanks.
Environment
Device: iPad Air (5th generation, M1)
OS Version: iPadOS 26.1
Device Orientation Lock: OFF
Stage Manager / Multitasking: Disabled
App Mode: Full screen (UIRequiresFullScreen = true)
Supported Orientations:
iPhone: Portrait + Landscape
iPad: Landscape only
Description
On iPadOS 26.x, when device orientation lock is OFF, iPad apps that support only landscape orientation can be displayed in portrait orientation, even though portrait is explicitly not supported for iPad.
This issue:
Occurs not only at app launch
Can also happen during runtime, such as:
Returning to the app from background
Unlocking the device
Rotating the device while the app is running
Switching focus (Control Center, Notification Center, multitasking gestures)
When orientation lock is ON, the system consistently respects the app’s supported interface orientations and the issue does not occur.
This behavior is a regression in iPadOS 26.x.
Expected Behavior
Regardless of device orientation lock state:
The system should never display an app in an unsupported orientation
supportedInterfaceOrientations must always be enforced
Physical device orientation should only be applied within supported orientations
Actual Behavior
With orientation lock OFF:
The system can force the app into portrait orientation
This happens even though portrait is not listed in UISupportedInterfaceOrientations~ipad
The app UI becomes incorrectly laid out or broken
With orientation lock ON:
Orientation behavior is correct and stable
This suggests iPadOS 26.x is allowing device orientation to override supportedInterfaceOrientations during runtime.
Info.plist Configuration
UIRequiresFullScreen
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
Topic:
UI Frameworks
SubTopic:
General
Problem
For a mac app, when the Settings view that uses @Environment(\.dismiss) it causes the subview's models to be created multiple times.
Environment
macOS: 26.2 (25C56)
Feedback
FB21424864
Code
App
@main
struct DismissBugApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
Settings {
SettingsView()
}
}
}
ContentView
struct ContentView: View {
var body: some View {
Text("Content")
}
}
SettingsView
struct SettingsView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
VStack {
Text("Settings")
SectionAView()
}
}
}
SectionAView
struct SectionAView: View {
@State private var model = SectionAViewModel()
var body: some View {
Text("A")
.padding(40)
}
}
SectionAViewModel
@Observable
class SectionAViewModel {
init() {
print("SectionAViewModel - init")
}
deinit {
print("SectionAViewModel - deinit")
}
}
Steps to reproduce (refer to the attached video)
1 - Run the app on the mac
2 - Open app's Settings
3 - Notice the following logs being printed in the console:
SectionAViewModel - init
SectionAViewModel - init
4 - Tap on some other app, so that the app loses focus
5 - Notice the following logs being printed in the console:
SectionAViewModel - init
SectionAViewModel - deinit
6 - Bring the app back to focus
7 - Notice the following logs being printed in the console:
SectionAViewModel - init
SectionAViewModel - deinit
Refer to screen recording
Topic:
UI Frameworks
SubTopic:
SwiftUI
NSApplicationDelegate.application(_:open:) gets the files it needs to read from the file URLs given. There are similar older functions that use a String to identify the file. What format are those strings expecting? A path name? An URL?
I have the following code (compile as a standalone file):
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (strong) NSWindow *window;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
// Create main window
self.window = [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 100, 800, 600)
styleMask:(NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskResizable |
NSWindowStyleMaskMiniaturizable)
backing:NSBackingStoreBuffered
defer:NO];
[self.window setTitle:@"Nested ScrollView Demo"];
[self.window makeKeyAndOrderFront:nil];
// Split view controller
NSSplitViewController *splitVC = [[NSSplitViewController alloc] init];
// Sidebar
NSViewController *sidebarVC = [[NSViewController alloc] init];
sidebarVC.view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 600)];
sidebarVC.view.wantsLayer = YES;
NSSplitViewItem *sidebarItem = [NSSplitViewItem sidebarWithViewController:sidebarVC];
sidebarItem.minimumThickness = 150;
sidebarItem.maximumThickness = 400;
[splitVC addSplitViewItem:sidebarItem];
// Content view controller
NSViewController *contentVC = [[NSViewController alloc] init];
// Vertical scroll view (outer)
NSScrollView *verticalScrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 600, 600)];
verticalScrollView.automaticallyAdjustsContentInsets = YES;
verticalScrollView.hasVerticalScroller = YES;
verticalScrollView.hasHorizontalScroller = NO;
verticalScrollView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
NSView *verticalContent = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 600, 1200)];
verticalContent.wantsLayer = YES;
verticalContent.layer.backgroundColor = [[NSColor blueColor] CGColor];
[verticalScrollView setDocumentView:verticalContent];
// Add several horizontal scroll sections
CGFloat sectionHeight = 150;
for (int i = 0; i < 5; i++) {
// Horizontal scroll view inside section
NSScrollView *horizontalScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, verticalContent.frame.size.height - (i+1)*sectionHeight - i*20, 600, sectionHeight)];
horizontalScroll.hasHorizontalScroller = YES;
horizontalScroll.hasVerticalScroller = NO;
horizontalScroll.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
NSView *horizontalContent = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 1200, sectionHeight)];
horizontalContent.wantsLayer = YES;
// Add labels horizontally
for (int j = 0; j < 6; j++) {
NSTextField *label = [NSTextField labelWithString:[NSString stringWithFormat:@"Item %d-%d", i+1, j+1]];
label.frame = NSMakeRect(20 + j*200, sectionHeight/2 - 15, 180, 30);
[horizontalContent addSubview:label];
}
horizontalScroll.documentView = horizontalContent;
[verticalContent addSubview:horizontalScroll];
}
contentVC.view = verticalScrollView;
NSSplitViewItem *contentItem = [NSSplitViewItem splitViewItemWithViewController:contentVC];
contentItem.automaticallyAdjustsSafeAreaInsets = YES;
contentItem.minimumThickness = 300;
[splitVC addSplitViewItem:contentItem];
self.window.contentViewController = splitVC;
// Sidebar label
NSTextField *label = [NSTextField labelWithString:@"Sidebar"];
label.translatesAutoresizingMaskIntoConstraints = NO;
[sidebarVC.view addSubview:label];
[NSLayoutConstraint activateConstraints:@[
[label.centerXAnchor constraintEqualToAnchor:sidebarVC.view.centerXAnchor],
[label.centerYAnchor constraintEqualToAnchor:sidebarVC.view.centerYAnchor]
]];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
AppDelegate *delegate = [[AppDelegate alloc] init];
[app setDelegate:delegate];
[app run];
}
return 0;
}
Obviously, since the contents of the right part (the content of the sidebar) has its content inset, the horizontal scrolling views cannot extend to the left beneath the sidebar. I can change line 39 to say verticalScrollView.automaticallyAdjustsContentInsets = NO; which will make the inner horizontal scroll views able to extend below the sidebar, but then I'd lose out on the automatic inset management to not have other content overlap beneath the sidebar. So what can I do here? I've tried manually changing the frame of the inner scroll views to start on a negative x, but that does not allow me to scroll all the way to the leftmost content. I'm hoping I won't have to adjust for safe areas manually for the outer scroll view.
I'd also appreciate tips on how to fix the fact that veritical scrolling doesn't work when your mouse is in a horizontal scroll view.
Thanks!
P.S. same thing also exists on UIKit.
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!
Topic:
UI Frameworks
SubTopic:
SwiftUI
Code example:
//
// ListSafeAreaBarKeyboardTextField.swift
// Exploration
import SwiftUI
import Foundation
struct ListSafeAreaBarKeyboardTextField: View {
@State private var typedText: String = ""
@FocusState private var focusingTextField: Bool
private let items = Array(1...16)
var body: some View {
ScrollViewReader { proxy in
List(items, id: \.self) { number in
Text("Item \(number)")
.id(number)
}
.onAppear {
if let lastItem = items.last {
proxy.scrollTo(lastItem, anchor: .bottom)
}
}
.onChange(of: focusingTextField) { oldValue, newValue in
// This simply won't work
// ~ 12th - 16th item will still get covered by keyboard
if newValue == true {
// Delay to allow keyboard animation to complete
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
if let lastItem = items.last {
withAnimation {
proxy.scrollTo(lastItem, anchor: .top)
}
}
}
}
}
}
.scrollDismissesKeyboard(.interactively)
.safeAreaBar(edge: .bottom) {
TextField("Type here", text: $typedText, axis: .vertical)
.focused($focusingTextField)
// Design
.padding(.horizontal, 16)
.padding(.vertical, 10)
.glassEffect()
// Paddings
.padding(.horizontal, 24)
.padding(.vertical, 12)
}
}
}
I have a Mac application that uses the NSEvent.addLocalMonitorForEvents API to receive all mouse movement events. It receives all the mouse movement events and calculate the event reporting rate.
The code used as following:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.frame(width: 400, height: 400)
.padding()
.onAppear() {
// here
NSEvent.addLocalMonitorForEvents(matching: [.mouseMoved]) { event in
print(event.timestamp)
return event
}
}
}
}
With the exact same code, before I upgraded my macOS to the latest version 26.2, I could receive approximately 460+ mouse events per second, this matched the hardware reporting frequency of my mouse device perfectly.
However, after upgrading to version 26.2, I noticed that the number of mouse events received per second is limited to match the screen refresh rate: when I set the screen refresh rate to 60Hz, I only receive 60 mouse events per second; when set to 120Hz, I receive 120 events per second.
It is clear that some changes has be delivered in macOS 26.2, which by default downsamples the frequency of mouse events reported to applications to align with the screen refresh rate.
The question is how can I reteive all the original mouse events in macOS 26.2? I tried to search and dig, bug no any related APIs found.
Topic:
UI Frameworks
SubTopic:
AppKit