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.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

Pass data to an @Observable model
Overview I have a navigation split view. The detail view contains a model now this model depends on id from the parent view. Questions How can I pass data from the parent view and yet create the view in the detail view? Or should I be pass the model from the parent view, but the problem is the parent view needs to persist model. Or is there a better approach?
6
0
280
4w
CarPlay handoff to MapKit fails on n+1 attempts
A CarPlay app with the carplay-fueling entitlement displays a list of stations. Tapping a station hands off to the Maps app for directions and navigation. Sometimes the handoff will return unsuccessful from the open call. The first attempt will succeeed. I immedediately return to my app and select a different station. The second attemp may succeed or it may fail. If the handoff attempt fails I can switch to the Maps app, return to MyApp, tap the same station row that just failed and the handoff will succeed. The issue is across multiple iOS versions (18 and 26) and multiple devices. Looking at the sysdiagnose logs, a successful handoff looks like this: 2026-06-26 15:56:27.762040 lsd: pid 14570 requests to open URL with scheme <private> 2026-06-26 15:56:27.768475 lsd: [FBSSystemService][0xee43] Sending request to open "com.apple.Maps" 2026-06-26 15:56:27.782145 lsd: [FBSSystemService][0xee43] Request successful: <BSProcessHandle ... Maps:17170; valid: YES> A failed handoff looks like this: 2026-06-26 17:05:00.162432 lsd: pid 14570 requests to open URL with scheme <private> 2026-06-26 17:05:00.171618 lsd: [FBSSystemService][0x3d16] Sending request to open "com.apple.Maps" 2026-06-26 17:05:00.173776 SpringBoard: Received request to open "com.apple.Maps" with url "maps:<private>" from lsd:122 on behalf of MyApp:14570. 2026-06-26 17:05:00.174110 SpringBoard: Received untrusted open application request for "com.apple.Maps" from <FBApplicationProcess ... app<au.com.philk.MyApp>:14570> 2026-06-26 17:05:00.175103 SpringBoard: Open "com.apple.Maps" request from lsd:122 failed with error: FBSOpenApplicationServiceErrorDomain; code: 1 ("RequestDenied") Reason: Application au.com.philk.MyApp is neither visible nor entitled, so may not perform un-trusted user actions. Underlying: FBSOpenApplicationErrorDomain; code: 3 ("Security") Looking more closely at the logs, the template UI is brought forward: CarPlay: DBApplicationSceneHostViewController; au.com.philk.MyApp; proxy: com.apple.CarPlayTemplateUIHost RunningBoard briefly grants MyApp foreground / render assertions: Foreground Template App FBWorkspace (ForegroundFocal) Set darwin role to: UserInteractiveFocal visibility is yes However, SpringBoard also records MyApp as background: 2026-06-26 17:04:53.709527 SpringBoard: Application process state changed for au.com.philk.MyApp: taskState: Running; visibility: Background The denied open at 17:05:00 appears to use SpringBoard's application visibility/trust decision, not the fact that the user is actively interacting with MyApp's CarPlay template UI. The following is logged: Application au.com.philk.MyApp is neither visible nor entitled, so may not perform un-trusted user actions. I have tried two different ways to pass/open the URL, and both will fail, usually after the first attempt. A plain maps:// URL Creating a MapItem and using: MKMapItem.openInMaps(launchOptions:from:completionHandler:) I wonder if this is the same or similar bug to the one reported here? https://developer.apple.com/forums/thread/787788?answerId=843556022#843556022 What is the root cause of the random failures? Any help or pointers will be appreciated.
5
0
347
4w
Horizontal Size Classes on iPhone in iOS 27
In iOS 27, willTransition(to:with:), registerForTraitChanges(), and other mechanisms to monitor size classes do not change when an iPhone interface is resized. Only viewWillTransition(to:with:) is invoked with a new size. And this only happens on the iPhone: the iPad continues to work as it has in the past. It appears that this is intended behavior. That is not to say that it's intuitive behavior. Many experienced developers are encountering the "horizontal size is always compact" behavior and immediately thinking "this must be a beta bug": https://fatbobman.com/en/posts/from-size-class-to-available-space/ But it's not. I get that the new size class behavior is expressing static device semantics and is no longer a dynamic size indicator. The problem is that the tools we have been using to build layouts for the past decade use size classes as dynamic sizing indicators. Storyboards can contain variations that specify whether a constraint is used for regular or compact widths/ heights. Developers have used this ability to automatically adjust layouts as the size classes change. In one case, I use this capability to adjust a top-over-bottom layout in a portrait configuration to a side-by-side in a landscape configuration: switching centering, leading/trailing, and aspect ratios to fit the available size. I suspect that many developers who have taken the time to create a unique layout for an iPad are doing something similar. (Ironically, the folks who treated an iPad as a big iPhone are the ones least affected by this change.) When iPadOS got the ability to resize interfaces (as UIScene windows), I made sure that the automatic size class contraints worked correctly and made adjustments as necessary. That work now has to be discarded and switched over to something more universal. If this is truly the intended behavior going forward, time needs to be invested in updating the tooling behind automatic constraint variations: There should be warnings when the storyboard is compiled. I have dozens of automatic contraints embedded in the storyboard: and they're hard to find (each subview has its own contraints, so it's a manual traversal of a huge tree). There should be runtime warnings that your code that inspects size classes won't be executed. This was the biggest "what the hell is going on?" when trying to resize the interface the first time. At a higher level, Apple engineers have described what is happening. They have not explained why the iPhone is behaving differently than an iPad. And that's the root of this whole situation being unintuitive. We've got no clue. And developers without a clue are unlikely to adopt a new technology. It's essential that Apple explains this change in more detail. Yes, you're going to have to obfuscate it and make us read between the lines, but it's got to be done. (Everyone understands the changes regarding mainScreen wink wink, for example.) A reply in this thread would be a good place to start this explanation.
5
5
1.1k
4w
SwiftUI Slider onEditingChanged is unreliable on iOS 26
For information I stumbled upon a regression with SwiftUI Slider on iOS 26. Its onEditingChanged closure might be called twice when interaction ends, with a final Boolean incorrect value of true provided to the closure. As a result apps cannot reliably rely on this closure to detect when an interaction with the slider starts or ends. I filed a feedback under FB20283439 (iOS 26.0 regression: Slider onEditingChanged closure is unreliable).
8
10
728
4w
CATiledLayer flashes and re-draws entirely when re-drawing a single tile
I have filed a bug report for this (FB17734946), but I'm posting it here verbatim in case others have the same issue and in hopes of getting attention from an Apple engineer sooner. When calling setNeedsDisplayInRect on a CATiledLayer - or a UIView whose backing layer is CATiledLayer - one would expect to re-draw only a region identified by the rect passed to the method. This is even written in the documentation for the class: "Regions of the layer may be invalidated using the setNeedsDisplayInRect: method however the update will be asynchronous. While the next display update will most likely not contain the updated content, a future update will." However, upon calling this method, CATiledLayer redraws whole contents instead of just the tile at the specified rect, and it flashes when doing so. It behaves exactly the same as if one had called setNeedsDisplay without passing any rect; all contents are cleared and re-drawn again. I'm 100% sure I've passed in the correct rect of the exact tile that I need to redraw. I have even tried passing much smaller rects, but still the same. (And yes, the rect I've passed accounts for the current level of detail.) I have found this GitHub repo https://github.com/frankus/NetPhotoScroller, which based on discussion from here https://forums.macrumors.com/threads/catiledlayer-blanks-out-tiles-when-redrawing.1333948/ aims at solving these issues by using two private methods on CATiledLayer class: (void)setNeedsDisplayInRect:(CGRect)r levelOfDetail:(int)level; (BOOL)canDrawRect:(CGRect)rect levelOfDetail:(int)level; I have explored the repo in detail, however I wasn't able to test exactly this code from the GitHub repo. I have tried using those two private methods myself (through an Objective-C class that defines the methods in the header file and then a swift class which inherits it), but I couldn't solve the issue; the flashing and the full re-draw is still there. After doing a lot of research, the conclusion seems to be that one cannot use CATiledLayer with contents that are downloaded remotely, on demand, as tiles are being requested. I have, however, found one interesting thing which seems to work so far: before calling setNeedsDisplayInRect (or just setNeedsDisplay, as they behave the same for CATiledLayer in my testing), cache the current layer's contents, and after calling setNeedsDisplay (or setNeedsDisplayInRect), restore the contents back to the layer. This prevents flashing and preserves any tiles that were drawn at the time of the re-draw. let c = tiledLayer.contents tiledLayer.setNeedsDisplay(tileRect) tiledLayer.contents = c However! Docs clearly state the warning: Do not attempt to directly modify the contents property of a CATiledLayer object. Doing so disables the ability of a tiled layer to asynchronously provide tiled content, effectively turning the layer into a regular CALayer object. I believe this message implies modifying the contents property with some raw content, like image data, and that it may be safe to re-apply the existing contents (which are in my testing of type CAImageProvider) -- but I can't rely on an implementation detail in my production app. I have tested this and confirmed that the bug appears on: iPhone 14 Pro, iOS 18.5 iPhone 13 Pro, iOS 17.5.1 iPhone 5s, iOS 15.8.3 iPad Pro 1st gen, iPadOS 18.4.1 a couple simulator versions I can also confirm that the fix (to re-apply contents property) is also working properly on all these versions. Is this expected behavior, that tiled layer redraws itself entirely instead of redrawing specific tiles? Is it safe to modify contents of a CATiledLayer by re-applying the existing contents? If not, is there an alternative to avoid flashing?
4
1
489
4w
UIContextualAction doesn't scale for dynamic font under Liquid Glass
Experiencing an issue with UIContextualAction title text respecting the user's Dynamic Type / preferred content size category when Liquid Glass is active. It's setup using a UITableView with trailing swipe actions via trailingSwipeActionsConfigurationForRowAt. Under Liquid Glass, the contextual action buttons render as floating glass pills, but the title text within them remains at a fixed size regardless of the Dynamic Type setting. Increasing the preferred content size category to accessibility sizes has no visible effect on the action label font size. Any suggestions to make this scalable for dynamic font
1
2
218
Jul ’26
Cannot download voices in the iOS 26.5 Simulator
The issue can be reproduced as follows : Launch the iOS 26.5 Simulator. Go to the Settings app. Tap Accessibility. Tap Spoken Content. Turn on Speak Selection. Tap Voices. An empty view gets opened, in which no language can be selected. How can voices be downloaded in the iOS 26.5 Simulator ? Note: There is not such issue in the iOS 18.5 Simulator. Note: There is not such issue in a real iOS 26.5 Device.
2
0
221
Jul ’26
toolbar` bottomBar disappears after rotating iPhone from portrait to landscape
I have a SwiftUI detail view with a native toolbar. On iPhone, the bottom toolbar appears correctly in portrait. After rotating the device to landscape, the bottom toolbar disappears. It does not come back unless the detail view is rebuilt. I would like to keep the native toolbar appearance and behavior, especially the iOS toolbar/glass effect. I do not want to replace it with a custom safeAreaInset bar. Environment Platform: iOS Current target/system: iOS 27 UI framework: SwiftUI Device idiom: iPhone The issue happens when rotating from portrait to landscape. Expected behavior The native bottom toolbar remains visible after device rotation. Actual behavior The native bottom toolbar is visible in portrait, but disappears after rotating to landscape. Core code The main view attaches toolbar content like this: private var contentWithToolbarAndSheets: some View { coreLayout .slateNavigationBarTitleDisplayModeInline() .toolbar { #if os(iOS) ToolbarItem(placement: .principal) { VStack(spacing: 0) { Text(String(localized: "第 \(scene.safeNumber) 场")) .font(.headline) .fontWeight(.semibold) .lineLimit(1) Text(scene.safeSetName) .font(.subheadline) .foregroundStyle(.secondary) .lineLimit(1) } } #endif bottomBarContent } #if os(macOS) .navigationTitle(String(localized: "第 \(scene.safeNumber) 场")) .navigationSubtitle(scene.safeSetName) #endif .slateBottomBarBackgroundHidden() } The bottom toolbar content: @ToolbarContentBuilder private var bottomBarContent: some ToolbarContent { #if os(iOS) let bar = scriptBottomBar ToolbarItem(placement: .slateBottomBar) { bar.monitorButton } if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.fixed, placement: .slateBottomBar) } ToolbarItem(placement: .slateBottomBar) { bar.soundRollButton } if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.flexible, placement: .slateBottomBar) } ToolbarItem(placement: .status) { bar.principalContent } ToolbarItem(placement: .slateBottomBar) { bar.historyButton } if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.fixed, placement: .slateBottomBar) } if isRecording { if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.fixed, placement: .slateBottomBar) } ToolbarItem(placement: .slateBottomBar) { bar.trailingContent } } #endif } The compatibility wrappers are: func slateBottomBarBackgroundHidden() -> some View { #if os(iOS) self.toolbarBackground(.hidden, for: .bottomBar) #else self #endif } extension ToolbarItemPlacement { static var slateBottomBar: ToolbarItemPlacement { #if os(iOS) .bottomBar #else .automatic #endif } } Workaround that made it reappear Previously, I had a workaround that listened to size class and orientation changes, then forced the detail view to rebuild by clearing and restoring the selected scene: #if os(iOS) .onChange(of: horizontalSizeClass) { _, _ in forceRefreshByClearingSidebarSelection() } .onChange(of: verticalSizeClass) { _, _ in forceRefreshByClearingSidebarSelection() } .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in let orientation = UIDevice.current.orientation guard orientation.isPortrait || orientation.isLandscape else { return } forceRefreshByClearingSidebarSelection() } #endif #if os(iOS) private func forceRefreshByClearingSidebarSelection() { guard UIDevice.current.userInterfaceIdiom == .phone else { return } let currentSceneID = session.selectedSceneID session.selectedSceneID = nil DispatchQueue.main.async { if session.selectedSceneID == nil { session.selectedSceneID = currentSceneID } } } #endif This made the toolbar reappear after rotation, but it is too heavy because it rebuilds the selected scene/detail view. Things I tried Moved the center toolbar item from .status to .bottomBar. Result: did not fix the disappearing toolbar. Kept native toolbar, added a local toolbarRefreshToken, updated it on horizontalSizeClass / verticalSizeClass changes, and attached .id(toolbarRefreshToken) to toolbar item contents. Result: did not fix it. Removed .toolbarBackground(.hidden, for: .bottomBar). Result: did not fix it. Replacing the toolbar with safeAreaInset(edge: .bottom) works visually in terms of persistence, but loses the native toolbar/glass behavior, so this is not acceptable for this app. Question Is this expected behavior for SwiftUI bottom toolbars in compact-height landscape on iPhone, or is this a SwiftUI toolbar invalidation bug? Is there a recommended way to keep native .toolbar / .bottomBar behavior stable across portrait-to-landscape rotation without forcing the entire detail view to rebuild?
Topic: UI Frameworks SubTopic: SwiftUI
0
1
105
Jul ’26
Custom UI over the Picture in Picture window for AVPlayerInterstitialEvent items — is there an official way?
I attach an ad in front of the main video using AVPlayerInterstitialEvent, and PiP works across the interstitial→content transition. I’ve noticed that some apps, while in Picture in Picture, show additional UI that: displays the remaining time of the interstitial item, and lets the user skip the interstitial item and switch to the main video. As far as I know, the AVPictureInPictureController window is system-drawn and can’t be customized by the developer. So my questions are: Is there an official/supported path to present this kind of UI (a remaining-time indicator and a skip control for the interstitial item) over the PiP window? If so, what is the mechanism — is it a system control that gets forwarded to a delegate, framework-provided interstitial UI, or When the interstitial is skipped this way, does the framework return to the primary item automatically, or does the app drive it? I’d really appreciate any insight intodone. Thanks!
0
0
188
Jul ’26
TextField format, integer limits and fractions not applied
Hi Apple-Team, the format of a text field, in my case a percentage with one decimal place, is not applied when a button is pressed and the view is exited using dismiss. It is only used when another field receives focus. A button is not a focusable object, and this is a problem. This allows you to specify more decimal places, resulting in a saved value with unwanted decimal places. It's even worse when you specify integer limits and the value exceeds the limit. Do you always have to check the value before saving it? What's the point of having a format then? Some example images: The items in the list have a fraction limit of 8. The field has integer limit 2 and 1 fraction. When focusing a different field the format is applied. Here the code I used: struct Item: Identifiable, Hashable { var id: Int var value: Double } struct WrongFractionsListView: View { @State private var items: [Item] = [ Item(id: 1, value: 0.225), Item(id: 2, value: 0.377), Item(id: 3, value: 0.241)] enum ItemTransfer: Hashable { case new } var body: some View { List { ForEach(items) { item in HStack { Text("\(item.id)") Spacer() Text("\(item.value, format: .percent.precision(.fractionLength(8)))") } } } .navigationDestination(for: ItemTransfer.self) { _ in WrongFractionsEditorView(items: $items) } .toolbar{ ToolbarItem(placement: .topBarTrailing) { NavigationLink(value: ItemTransfer.new) { Image(systemName: "plus") } } } } } #Preview { NavigationStack { WrongFractionsListView() } } struct WrongFractionsEditorView: View { @Environment(\.dismiss) var dismiss @State private var percentValue: Double = 0 @State private var testValue: String = "" @Binding var items: [Item] var body: some View { Form { TextField("(%)", value: $percentValue, format: .percent.precision(.integerAndFractionLength(integerLimits: 0...2, fractionLimits: 0...1))) .keyboardType(.decimalPad) TextField("Just for Focus", text: $testValue) } .navigationTitle("Percent Fractions") .toolbar{ ToolbarItem(placement: .topBarTrailing) { Button { saveAndClose() } label: { Image(systemName: "checkmark") } } } } private func saveAndClose() { let max = items.max { $0.id < $1.id}!.id let item: Item = .init(id: max+1, value: percentValue) items.append(item) dismiss() } } #Preview { @Previewable @State var items: [Item] = [ Item(id: 1, value: 0.225), Item(id: 2, value: 0.377), Item(id: 3, value: 0.241)] NavigationStack { WrongFractionsEditorView(items: $items) } } How can I fix this? Thank you Christian
2
0
196
Jul ’26
MapKit Pitch
I have a navigation app in production that works great. I recently integrated CarPlay, and I'm trying to use a more "horizon view" by increasing the camera pitch during navigation. Specifically, on a CarPlay screen with a resolution of 800×480, I'm trying to use a distance of 1000 m with a pitch of 60°, but MapKit automatically clamps the pitch to a bird's-eye view. If I reduce the distance to 800 m, for example, it works just fine. I'd argue that having a better horizon view during navigation is a safety feature, as users, especially truck drivers, need to see well ahead. Most truck navigation systems provide this by default, so I'm wondering if there's any workaround to achieve this without MapKit clamping the pitch? I found the following in the documentation, which seems pretty clear, but I thought I'd ask if anyone has found a workaround...? From docs: "The class may clamp the value in this property to a maximum value to maintain map readability. There’s no fixed maximum value, though, because the actual maximum value is dependent on the altitude of the camera." MapCamera( centerCoordinate: locationManager.coordinate, distance: 1000, heading: locationManager.heading, pitch: 60 )
0
0
145
Jul ’26
Presenting content on Connected Display not working on iOS 27
I have an app that displays different content on a connected display (following this guide). It's working fine on iOS 26 but no longer is working in iOS 27 (both dev betas) + the latest SDKs. I tried to find any update notes but I couldn't find anything so I'm not sure if I'm doing something wrong or if it's an actual bug. I was able to simplify it down to the simplest case here: import SwiftUI // App Delegate to setup the scene delegate @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { print("Calling didFinishLaunchingWithOptions") return true } func application(_: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options _: UIScene.ConnectionOptions) -> UISceneConfiguration { print("Calling configurationForConnecting") let sceneConfig = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role) sceneConfig.delegateClass = WindowSceneDelegate.self return sceneConfig } } // Scene delegate that sets up the view class WindowSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo _: UISceneSession, options _: UIScene.ConnectionOptions) { print("Calling scene(willConnectTo:) with role \(scene.session.role)") guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) if scene.session.role == .windowExternalDisplayNonInteractive { window.rootViewController = UIHostingController(rootView: ExternalDisplay()) } else { window.rootViewController = UIHostingController(rootView: ContentView()) } self.window = window window.makeKeyAndVisible() } } struct ExternalDisplay: View { var body: some View { Text("Other World!") } } struct ContentView: View { var body: some View { Text("Hello, world!") } } I also have my Info showing "Enable Multiple Scenes" set to true. I can screen mirror this app to my Mac (same result with an Apple TV). On iOS 26, on my iPhone, I'd see "Hello World!" and on the connected display, I'd see "Other World!". On iOS 27, this is no longer the case. On my connected display, I just see "Hello World". I'm trying to figure out if I've missed something or if this is a dev beta bug.
2
0
293
Jul ’26
Crash when selecting a lot of cells in UICollectionView
Hey, I am implementing a "Select All" functionality and experiencing a crash because of running out of memory when having a lot of cells. Calling .selectItem(at:animated:scrollPosition:) on 10k cells need 1.5GB and 20k needs 7GB (crashes on a real device). After selection is completed, memory goes down to normal levels. This broken both on iOS 18.5 and 26.5. Minimal example: https://github.com/martonfarago/collectionViewMemoryTest Is this a know issue? Is there another, maybe more efficient way of selecting all cells? M
Topic: UI Frameworks SubTopic: UIKit
3
0
193
Jul ’26
UITabBarAppearance with iOS27 Beta
iOS Version: iOS 27 Beta Xcode: Xcode27 Beta 2 I have a custom UITabBar subclass. The tab bar items are visible and selectable, and the selected state works, but the title color in the normal state is always rendered as white, even though I set a different normal title color. Simplified code let normalColor = UIColor.gray let selectedColor = UIColor.orange let bgColor = UIColor.black let font = UIFont.systemFont(ofSize: 10, weight: .semibold) let appearance = UITabBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundEffect = nil appearance.backgroundColor = bgColor appearance.shadowColor = .clear let itemAppearance = appearance.stackedLayoutAppearance itemAppearance.normal.titleTextAttributes = [ .font: font, .foregroundColor: normalColor ] itemAppearance.selected.titleTextAttributes = [ .font: font, .foregroundColor: selectedColor ] itemAppearance.normal.iconColor = normalColor itemAppearance.selected.iconColor = selectedColor appearance.stackedLayoutAppearance = itemAppearance appearance.inlineLayoutAppearance = itemAppearance appearance.compactInlineLayoutAppearance = itemAppearance tabBar.standardAppearance = appearance if #available(iOS 15.0, *) { tabBar.scrollEdgeAppearance = appearance } tabBar.backgroundColor = bgColor tabBar.isTranslucent = false The problem: The selected title/icon color works. The normal title color is ignored and stays white. This happens after moving to the newer tab bar appearance behavior / Liquid Glass environment. Question: Is there any additional configuration required for UITabBarAppearance so that the normal UITabBarItem title color is respected? Could unselectedItemTintColor, tintColor, scrollEdgeAppearance, or Liquid Glass behavior override normal.titleTextAttributes?
3
0
271
Jul ’26
NSApp.activate() does not work with menu bar (background) apps
NSApp(ignoringOtherApps:) is deprecated but there is no other working alternative for menu bar apps. NSApp.activate() does not work when no app windows are active and we want to show a window from a menu bar application. Making it impossible for the app to open a window and make it active. Is it really an intended behavior? Here is a sample project showing the issue: https://github.com/wojciech-kulik/macos-menu-bar-bug Steps to reproduce: Run the app. Focus some other app like Finder or Safari. Click on the app's menu bar icon and select "Open". The app window will appear below the other app's window, instead of being brought to the front. NSApp(ignoringOtherApps: true) works as expected though. I also created a feedback ticket: FB23508310
10
1
387
Jul ’26
Why does SwiftUI not come with an Environment entry for the current NavigationPath?
If I have a detail view, it can include a NavigationLink (with either a specific destination view, or a value to be resolved by the nearest .navigationDestination handler in to a view). But some operations cannot be captured by a NavigationLink. For example, perhaps this detail view is editing a list, and I have a button to insert a new item. I may wish to insert the new item, and then navigate to a further editor for the inserted item. I can't do that with a NavigationLink: NavigationLink { // 🚨 This is a @ViewBuilder/@ContentBuilder, and there are no guarantees about how often it is invoked. let newItem = dataSource.insertNewItem() ItemEditor(newItem) } label: { // ... } This is the use-case which NavigationPath or typed navigation stacks handle for us: Button { let newItem = dataSource.insertNewItem() navigationPath.append(newItem) } label: { // ... } .navigationDestination(for: Item.self) { item in ItemEditor(item) } Unfortunately, while NavigationLink is able to inspect the View's environment, find the nearest NavigationStack, and push to it, there is no built-in @Environment key for programmatic navigation to do the same. Instead, developers need to add the path as an explicit state variable where the stack is declared, and manually pass it around or create their own @Environment keys, being diligent to ensure they always set that environment value in case some detail view happens to need to need programmatic navigation. I've never understood why. This seems to be a common problem in the ecosystem, and of course in UIKit you can always grab the nearest .navigationController, so I always thought it was an intentional omission. Was it? Should I file an enhancement request? Or is there a reason why this is not considered a good idea? Thanks
Topic: UI Frameworks SubTopic: SwiftUI
0
0
116
Jul ’26
SwiftUI 6 AttributeGraph warnings in console
On a MacBook Air M4 running macOS Sequoia 15.7.7, the following tiny code does warn inside the Xcode 26.3. Here is the whole console output: === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 110216 === === AttributeGraph: cycle detected through attribute 110216 === === AttributeGraph: cycle detected through attribute 110284 === === AttributeGraph: cycle detected through attribute 110284 === === AttributeGraph: cycle detected through attribute 110216 === === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 110216 === Here is the full code: import SwiftUI @main struct myApp: App { var body: some Scene { WindowGroup { BaseView() } } } struct BaseView: View { @State private var isWorking: Bool = false var body: some View { Button("Go") { Task { // AttributeGraph warnings await MainActor.run { isWorking = true } await MainActor.run { isWorking = false } // No warnings at all // DispatchQueue.main.async { isWorking = true } // DispatchQueue.main.async { isWorking = false } } } .disabled(isWorking) .padding() } } You can see with DispatchQueue.main.async {...}, warnings aren't there. After a few days struggling with different AI support (Claude, ChatGPT, Perplexity), I didn't find any way to fix my own code. This tiny code is just there to show the issue. I tested multiple workarounds without finding one that fits to my app context. Thanks in advance for your support.
Topic: UI Frameworks SubTopic: SwiftUI
4
0
219
Jul ’26
Pass data to an @Observable model
Overview I have a navigation split view. The detail view contains a model now this model depends on id from the parent view. Questions How can I pass data from the parent view and yet create the view in the detail view? Or should I be pass the model from the parent view, but the problem is the parent view needs to persist model. Or is there a better approach?
Replies
6
Boosts
0
Views
280
Activity
4w
CarPlay handoff to MapKit fails on n+1 attempts
A CarPlay app with the carplay-fueling entitlement displays a list of stations. Tapping a station hands off to the Maps app for directions and navigation. Sometimes the handoff will return unsuccessful from the open call. The first attempt will succeeed. I immedediately return to my app and select a different station. The second attemp may succeed or it may fail. If the handoff attempt fails I can switch to the Maps app, return to MyApp, tap the same station row that just failed and the handoff will succeed. The issue is across multiple iOS versions (18 and 26) and multiple devices. Looking at the sysdiagnose logs, a successful handoff looks like this: 2026-06-26 15:56:27.762040 lsd: pid 14570 requests to open URL with scheme <private> 2026-06-26 15:56:27.768475 lsd: [FBSSystemService][0xee43] Sending request to open "com.apple.Maps" 2026-06-26 15:56:27.782145 lsd: [FBSSystemService][0xee43] Request successful: <BSProcessHandle ... Maps:17170; valid: YES> A failed handoff looks like this: 2026-06-26 17:05:00.162432 lsd: pid 14570 requests to open URL with scheme <private> 2026-06-26 17:05:00.171618 lsd: [FBSSystemService][0x3d16] Sending request to open "com.apple.Maps" 2026-06-26 17:05:00.173776 SpringBoard: Received request to open "com.apple.Maps" with url "maps:<private>" from lsd:122 on behalf of MyApp:14570. 2026-06-26 17:05:00.174110 SpringBoard: Received untrusted open application request for "com.apple.Maps" from <FBApplicationProcess ... app<au.com.philk.MyApp>:14570> 2026-06-26 17:05:00.175103 SpringBoard: Open "com.apple.Maps" request from lsd:122 failed with error: FBSOpenApplicationServiceErrorDomain; code: 1 ("RequestDenied") Reason: Application au.com.philk.MyApp is neither visible nor entitled, so may not perform un-trusted user actions. Underlying: FBSOpenApplicationErrorDomain; code: 3 ("Security") Looking more closely at the logs, the template UI is brought forward: CarPlay: DBApplicationSceneHostViewController; au.com.philk.MyApp; proxy: com.apple.CarPlayTemplateUIHost RunningBoard briefly grants MyApp foreground / render assertions: Foreground Template App FBWorkspace (ForegroundFocal) Set darwin role to: UserInteractiveFocal visibility is yes However, SpringBoard also records MyApp as background: 2026-06-26 17:04:53.709527 SpringBoard: Application process state changed for au.com.philk.MyApp: taskState: Running; visibility: Background The denied open at 17:05:00 appears to use SpringBoard's application visibility/trust decision, not the fact that the user is actively interacting with MyApp's CarPlay template UI. The following is logged: Application au.com.philk.MyApp is neither visible nor entitled, so may not perform un-trusted user actions. I have tried two different ways to pass/open the URL, and both will fail, usually after the first attempt. A plain maps:// URL Creating a MapItem and using: MKMapItem.openInMaps(launchOptions:from:completionHandler:) I wonder if this is the same or similar bug to the one reported here? https://developer.apple.com/forums/thread/787788?answerId=843556022#843556022 What is the root cause of the random failures? Any help or pointers will be appreciated.
Replies
5
Boosts
0
Views
347
Activity
4w
Horizontal Size Classes on iPhone in iOS 27
In iOS 27, willTransition(to:with:), registerForTraitChanges(), and other mechanisms to monitor size classes do not change when an iPhone interface is resized. Only viewWillTransition(to:with:) is invoked with a new size. And this only happens on the iPhone: the iPad continues to work as it has in the past. It appears that this is intended behavior. That is not to say that it's intuitive behavior. Many experienced developers are encountering the "horizontal size is always compact" behavior and immediately thinking "this must be a beta bug": https://fatbobman.com/en/posts/from-size-class-to-available-space/ But it's not. I get that the new size class behavior is expressing static device semantics and is no longer a dynamic size indicator. The problem is that the tools we have been using to build layouts for the past decade use size classes as dynamic sizing indicators. Storyboards can contain variations that specify whether a constraint is used for regular or compact widths/ heights. Developers have used this ability to automatically adjust layouts as the size classes change. In one case, I use this capability to adjust a top-over-bottom layout in a portrait configuration to a side-by-side in a landscape configuration: switching centering, leading/trailing, and aspect ratios to fit the available size. I suspect that many developers who have taken the time to create a unique layout for an iPad are doing something similar. (Ironically, the folks who treated an iPad as a big iPhone are the ones least affected by this change.) When iPadOS got the ability to resize interfaces (as UIScene windows), I made sure that the automatic size class contraints worked correctly and made adjustments as necessary. That work now has to be discarded and switched over to something more universal. If this is truly the intended behavior going forward, time needs to be invested in updating the tooling behind automatic constraint variations: There should be warnings when the storyboard is compiled. I have dozens of automatic contraints embedded in the storyboard: and they're hard to find (each subview has its own contraints, so it's a manual traversal of a huge tree). There should be runtime warnings that your code that inspects size classes won't be executed. This was the biggest "what the hell is going on?" when trying to resize the interface the first time. At a higher level, Apple engineers have described what is happening. They have not explained why the iPhone is behaving differently than an iPad. And that's the root of this whole situation being unintuitive. We've got no clue. And developers without a clue are unlikely to adopt a new technology. It's essential that Apple explains this change in more detail. Yes, you're going to have to obfuscate it and make us read between the lines, but it's got to be done. (Everyone understands the changes regarding mainScreen wink wink, for example.) A reply in this thread would be a good place to start this explanation.
Replies
5
Boosts
5
Views
1.1k
Activity
4w
SwiftUI Slider onEditingChanged is unreliable on iOS 26
For information I stumbled upon a regression with SwiftUI Slider on iOS 26. Its onEditingChanged closure might be called twice when interaction ends, with a final Boolean incorrect value of true provided to the closure. As a result apps cannot reliably rely on this closure to detect when an interaction with the slider starts or ends. I filed a feedback under FB20283439 (iOS 26.0 regression: Slider onEditingChanged closure is unreliable).
Replies
8
Boosts
10
Views
728
Activity
4w
CATiledLayer flashes and re-draws entirely when re-drawing a single tile
I have filed a bug report for this (FB17734946), but I'm posting it here verbatim in case others have the same issue and in hopes of getting attention from an Apple engineer sooner. When calling setNeedsDisplayInRect on a CATiledLayer - or a UIView whose backing layer is CATiledLayer - one would expect to re-draw only a region identified by the rect passed to the method. This is even written in the documentation for the class: "Regions of the layer may be invalidated using the setNeedsDisplayInRect: method however the update will be asynchronous. While the next display update will most likely not contain the updated content, a future update will." However, upon calling this method, CATiledLayer redraws whole contents instead of just the tile at the specified rect, and it flashes when doing so. It behaves exactly the same as if one had called setNeedsDisplay without passing any rect; all contents are cleared and re-drawn again. I'm 100% sure I've passed in the correct rect of the exact tile that I need to redraw. I have even tried passing much smaller rects, but still the same. (And yes, the rect I've passed accounts for the current level of detail.) I have found this GitHub repo https://github.com/frankus/NetPhotoScroller, which based on discussion from here https://forums.macrumors.com/threads/catiledlayer-blanks-out-tiles-when-redrawing.1333948/ aims at solving these issues by using two private methods on CATiledLayer class: (void)setNeedsDisplayInRect:(CGRect)r levelOfDetail:(int)level; (BOOL)canDrawRect:(CGRect)rect levelOfDetail:(int)level; I have explored the repo in detail, however I wasn't able to test exactly this code from the GitHub repo. I have tried using those two private methods myself (through an Objective-C class that defines the methods in the header file and then a swift class which inherits it), but I couldn't solve the issue; the flashing and the full re-draw is still there. After doing a lot of research, the conclusion seems to be that one cannot use CATiledLayer with contents that are downloaded remotely, on demand, as tiles are being requested. I have, however, found one interesting thing which seems to work so far: before calling setNeedsDisplayInRect (or just setNeedsDisplay, as they behave the same for CATiledLayer in my testing), cache the current layer's contents, and after calling setNeedsDisplay (or setNeedsDisplayInRect), restore the contents back to the layer. This prevents flashing and preserves any tiles that were drawn at the time of the re-draw. let c = tiledLayer.contents tiledLayer.setNeedsDisplay(tileRect) tiledLayer.contents = c However! Docs clearly state the warning: Do not attempt to directly modify the contents property of a CATiledLayer object. Doing so disables the ability of a tiled layer to asynchronously provide tiled content, effectively turning the layer into a regular CALayer object. I believe this message implies modifying the contents property with some raw content, like image data, and that it may be safe to re-apply the existing contents (which are in my testing of type CAImageProvider) -- but I can't rely on an implementation detail in my production app. I have tested this and confirmed that the bug appears on: iPhone 14 Pro, iOS 18.5 iPhone 13 Pro, iOS 17.5.1 iPhone 5s, iOS 15.8.3 iPad Pro 1st gen, iPadOS 18.4.1 a couple simulator versions I can also confirm that the fix (to re-apply contents property) is also working properly on all these versions. Is this expected behavior, that tiled layer redraws itself entirely instead of redrawing specific tiles? Is it safe to modify contents of a CATiledLayer by re-applying the existing contents? If not, is there an alternative to avoid flashing?
Replies
4
Boosts
1
Views
489
Activity
4w
UIContextualAction doesn't scale for dynamic font under Liquid Glass
Experiencing an issue with UIContextualAction title text respecting the user's Dynamic Type / preferred content size category when Liquid Glass is active. It's setup using a UITableView with trailing swipe actions via trailingSwipeActionsConfigurationForRowAt. Under Liquid Glass, the contextual action buttons render as floating glass pills, but the title text within them remains at a fixed size regardless of the Dynamic Type setting. Increasing the preferred content size category to accessibility sizes has no visible effect on the action label font size. Any suggestions to make this scalable for dynamic font
Replies
1
Boosts
2
Views
218
Activity
Jul ’26
Cannot download voices in the iOS 26.5 Simulator
The issue can be reproduced as follows : Launch the iOS 26.5 Simulator. Go to the Settings app. Tap Accessibility. Tap Spoken Content. Turn on Speak Selection. Tap Voices. An empty view gets opened, in which no language can be selected. How can voices be downloaded in the iOS 26.5 Simulator ? Note: There is not such issue in the iOS 18.5 Simulator. Note: There is not such issue in a real iOS 26.5 Device.
Replies
2
Boosts
0
Views
221
Activity
Jul ’26
toolbar` bottomBar disappears after rotating iPhone from portrait to landscape
I have a SwiftUI detail view with a native toolbar. On iPhone, the bottom toolbar appears correctly in portrait. After rotating the device to landscape, the bottom toolbar disappears. It does not come back unless the detail view is rebuilt. I would like to keep the native toolbar appearance and behavior, especially the iOS toolbar/glass effect. I do not want to replace it with a custom safeAreaInset bar. Environment Platform: iOS Current target/system: iOS 27 UI framework: SwiftUI Device idiom: iPhone The issue happens when rotating from portrait to landscape. Expected behavior The native bottom toolbar remains visible after device rotation. Actual behavior The native bottom toolbar is visible in portrait, but disappears after rotating to landscape. Core code The main view attaches toolbar content like this: private var contentWithToolbarAndSheets: some View { coreLayout .slateNavigationBarTitleDisplayModeInline() .toolbar { #if os(iOS) ToolbarItem(placement: .principal) { VStack(spacing: 0) { Text(String(localized: "第 \(scene.safeNumber) 场")) .font(.headline) .fontWeight(.semibold) .lineLimit(1) Text(scene.safeSetName) .font(.subheadline) .foregroundStyle(.secondary) .lineLimit(1) } } #endif bottomBarContent } #if os(macOS) .navigationTitle(String(localized: "第 \(scene.safeNumber) 场")) .navigationSubtitle(scene.safeSetName) #endif .slateBottomBarBackgroundHidden() } The bottom toolbar content: @ToolbarContentBuilder private var bottomBarContent: some ToolbarContent { #if os(iOS) let bar = scriptBottomBar ToolbarItem(placement: .slateBottomBar) { bar.monitorButton } if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.fixed, placement: .slateBottomBar) } ToolbarItem(placement: .slateBottomBar) { bar.soundRollButton } if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.flexible, placement: .slateBottomBar) } ToolbarItem(placement: .status) { bar.principalContent } ToolbarItem(placement: .slateBottomBar) { bar.historyButton } if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.fixed, placement: .slateBottomBar) } if isRecording { if #available(iOS 26.0, macOS 26.0, *) { ToolbarSpacer(.fixed, placement: .slateBottomBar) } ToolbarItem(placement: .slateBottomBar) { bar.trailingContent } } #endif } The compatibility wrappers are: func slateBottomBarBackgroundHidden() -> some View { #if os(iOS) self.toolbarBackground(.hidden, for: .bottomBar) #else self #endif } extension ToolbarItemPlacement { static var slateBottomBar: ToolbarItemPlacement { #if os(iOS) .bottomBar #else .automatic #endif } } Workaround that made it reappear Previously, I had a workaround that listened to size class and orientation changes, then forced the detail view to rebuild by clearing and restoring the selected scene: #if os(iOS) .onChange(of: horizontalSizeClass) { _, _ in forceRefreshByClearingSidebarSelection() } .onChange(of: verticalSizeClass) { _, _ in forceRefreshByClearingSidebarSelection() } .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in let orientation = UIDevice.current.orientation guard orientation.isPortrait || orientation.isLandscape else { return } forceRefreshByClearingSidebarSelection() } #endif #if os(iOS) private func forceRefreshByClearingSidebarSelection() { guard UIDevice.current.userInterfaceIdiom == .phone else { return } let currentSceneID = session.selectedSceneID session.selectedSceneID = nil DispatchQueue.main.async { if session.selectedSceneID == nil { session.selectedSceneID = currentSceneID } } } #endif This made the toolbar reappear after rotation, but it is too heavy because it rebuilds the selected scene/detail view. Things I tried Moved the center toolbar item from .status to .bottomBar. Result: did not fix the disappearing toolbar. Kept native toolbar, added a local toolbarRefreshToken, updated it on horizontalSizeClass / verticalSizeClass changes, and attached .id(toolbarRefreshToken) to toolbar item contents. Result: did not fix it. Removed .toolbarBackground(.hidden, for: .bottomBar). Result: did not fix it. Replacing the toolbar with safeAreaInset(edge: .bottom) works visually in terms of persistence, but loses the native toolbar/glass behavior, so this is not acceptable for this app. Question Is this expected behavior for SwiftUI bottom toolbars in compact-height landscape on iPhone, or is this a SwiftUI toolbar invalidation bug? Is there a recommended way to keep native .toolbar / .bottomBar behavior stable across portrait-to-landscape rotation without forcing the entire detail view to rebuild?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
1
Views
105
Activity
Jul ’26
Custom UI over the Picture in Picture window for AVPlayerInterstitialEvent items — is there an official way?
I attach an ad in front of the main video using AVPlayerInterstitialEvent, and PiP works across the interstitial→content transition. I’ve noticed that some apps, while in Picture in Picture, show additional UI that: displays the remaining time of the interstitial item, and lets the user skip the interstitial item and switch to the main video. As far as I know, the AVPictureInPictureController window is system-drawn and can’t be customized by the developer. So my questions are: Is there an official/supported path to present this kind of UI (a remaining-time indicator and a skip control for the interstitial item) over the PiP window? If so, what is the mechanism — is it a system control that gets forwarded to a delegate, framework-provided interstitial UI, or When the interstitial is skipped this way, does the framework return to the primary item automatically, or does the app drive it? I’d really appreciate any insight intodone. Thanks!
Replies
0
Boosts
0
Views
188
Activity
Jul ’26
onChange(of:initial:_:) changes when same value assigned
Overview When calling onChange(of:initial:_:) with initial as true, closure called even when the value assigned is the same as previous value (not just the first time, subsequently too). However when initial value is false it is called only when value changes. Questions Is this a bug? Am I missing something?
Replies
1
Boosts
0
Views
239
Activity
Jul ’26
TextField format, integer limits and fractions not applied
Hi Apple-Team, the format of a text field, in my case a percentage with one decimal place, is not applied when a button is pressed and the view is exited using dismiss. It is only used when another field receives focus. A button is not a focusable object, and this is a problem. This allows you to specify more decimal places, resulting in a saved value with unwanted decimal places. It's even worse when you specify integer limits and the value exceeds the limit. Do you always have to check the value before saving it? What's the point of having a format then? Some example images: The items in the list have a fraction limit of 8. The field has integer limit 2 and 1 fraction. When focusing a different field the format is applied. Here the code I used: struct Item: Identifiable, Hashable { var id: Int var value: Double } struct WrongFractionsListView: View { @State private var items: [Item] = [ Item(id: 1, value: 0.225), Item(id: 2, value: 0.377), Item(id: 3, value: 0.241)] enum ItemTransfer: Hashable { case new } var body: some View { List { ForEach(items) { item in HStack { Text("\(item.id)") Spacer() Text("\(item.value, format: .percent.precision(.fractionLength(8)))") } } } .navigationDestination(for: ItemTransfer.self) { _ in WrongFractionsEditorView(items: $items) } .toolbar{ ToolbarItem(placement: .topBarTrailing) { NavigationLink(value: ItemTransfer.new) { Image(systemName: "plus") } } } } } #Preview { NavigationStack { WrongFractionsListView() } } struct WrongFractionsEditorView: View { @Environment(\.dismiss) var dismiss @State private var percentValue: Double = 0 @State private var testValue: String = "" @Binding var items: [Item] var body: some View { Form { TextField("(%)", value: $percentValue, format: .percent.precision(.integerAndFractionLength(integerLimits: 0...2, fractionLimits: 0...1))) .keyboardType(.decimalPad) TextField("Just for Focus", text: $testValue) } .navigationTitle("Percent Fractions") .toolbar{ ToolbarItem(placement: .topBarTrailing) { Button { saveAndClose() } label: { Image(systemName: "checkmark") } } } } private func saveAndClose() { let max = items.max { $0.id < $1.id}!.id let item: Item = .init(id: max+1, value: percentValue) items.append(item) dismiss() } } #Preview { @Previewable @State var items: [Item] = [ Item(id: 1, value: 0.225), Item(id: 2, value: 0.377), Item(id: 3, value: 0.241)] NavigationStack { WrongFractionsEditorView(items: $items) } } How can I fix this? Thank you Christian
Replies
2
Boosts
0
Views
196
Activity
Jul ’26
Does SwiftUI pass views via the preference and environment, if so, how?
I am under the assumption that SwiftUI does pass views via preference atleast (navigationDestination, toolbar, sheet, alerts, popover etc.,). How does it maintain view identity and does it wrap the passing view in AnyView or internally it uses type inference magic, that is not available to us?. If it does not, then how does it pass them instead ?
Replies
0
Boosts
0
Views
127
Activity
Jul ’26
MapKit Pitch
I have a navigation app in production that works great. I recently integrated CarPlay, and I'm trying to use a more "horizon view" by increasing the camera pitch during navigation. Specifically, on a CarPlay screen with a resolution of 800×480, I'm trying to use a distance of 1000 m with a pitch of 60°, but MapKit automatically clamps the pitch to a bird's-eye view. If I reduce the distance to 800 m, for example, it works just fine. I'd argue that having a better horizon view during navigation is a safety feature, as users, especially truck drivers, need to see well ahead. Most truck navigation systems provide this by default, so I'm wondering if there's any workaround to achieve this without MapKit clamping the pitch? I found the following in the documentation, which seems pretty clear, but I thought I'd ask if anyone has found a workaround...? From docs: "The class may clamp the value in this property to a maximum value to maintain map readability. There’s no fixed maximum value, though, because the actual maximum value is dependent on the altitude of the camera." MapCamera( centerCoordinate: locationManager.coordinate, distance: 1000, heading: locationManager.heading, pitch: 60 )
Replies
0
Boosts
0
Views
145
Activity
Jul ’26
Presenting content on Connected Display not working on iOS 27
I have an app that displays different content on a connected display (following this guide). It's working fine on iOS 26 but no longer is working in iOS 27 (both dev betas) + the latest SDKs. I tried to find any update notes but I couldn't find anything so I'm not sure if I'm doing something wrong or if it's an actual bug. I was able to simplify it down to the simplest case here: import SwiftUI // App Delegate to setup the scene delegate @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { print("Calling didFinishLaunchingWithOptions") return true } func application(_: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options _: UIScene.ConnectionOptions) -> UISceneConfiguration { print("Calling configurationForConnecting") let sceneConfig = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role) sceneConfig.delegateClass = WindowSceneDelegate.self return sceneConfig } } // Scene delegate that sets up the view class WindowSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo _: UISceneSession, options _: UIScene.ConnectionOptions) { print("Calling scene(willConnectTo:) with role \(scene.session.role)") guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) if scene.session.role == .windowExternalDisplayNonInteractive { window.rootViewController = UIHostingController(rootView: ExternalDisplay()) } else { window.rootViewController = UIHostingController(rootView: ContentView()) } self.window = window window.makeKeyAndVisible() } } struct ExternalDisplay: View { var body: some View { Text("Other World!") } } struct ContentView: View { var body: some View { Text("Hello, world!") } } I also have my Info showing "Enable Multiple Scenes" set to true. I can screen mirror this app to my Mac (same result with an Apple TV). On iOS 26, on my iPhone, I'd see "Hello World!" and on the connected display, I'd see "Other World!". On iOS 27, this is no longer the case. On my connected display, I just see "Hello World". I'm trying to figure out if I've missed something or if this is a dev beta bug.
Replies
2
Boosts
0
Views
293
Activity
Jul ’26
Crash when selecting a lot of cells in UICollectionView
Hey, I am implementing a "Select All" functionality and experiencing a crash because of running out of memory when having a lot of cells. Calling .selectItem(at:animated:scrollPosition:) on 10k cells need 1.5GB and 20k needs 7GB (crashes on a real device). After selection is completed, memory goes down to normal levels. This broken both on iOS 18.5 and 26.5. Minimal example: https://github.com/martonfarago/collectionViewMemoryTest Is this a know issue? Is there another, maybe more efficient way of selecting all cells? M
Topic: UI Frameworks SubTopic: UIKit
Replies
3
Boosts
0
Views
193
Activity
Jul ’26
UITabBarAppearance with iOS27 Beta
iOS Version: iOS 27 Beta Xcode: Xcode27 Beta 2 I have a custom UITabBar subclass. The tab bar items are visible and selectable, and the selected state works, but the title color in the normal state is always rendered as white, even though I set a different normal title color. Simplified code let normalColor = UIColor.gray let selectedColor = UIColor.orange let bgColor = UIColor.black let font = UIFont.systemFont(ofSize: 10, weight: .semibold) let appearance = UITabBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundEffect = nil appearance.backgroundColor = bgColor appearance.shadowColor = .clear let itemAppearance = appearance.stackedLayoutAppearance itemAppearance.normal.titleTextAttributes = [ .font: font, .foregroundColor: normalColor ] itemAppearance.selected.titleTextAttributes = [ .font: font, .foregroundColor: selectedColor ] itemAppearance.normal.iconColor = normalColor itemAppearance.selected.iconColor = selectedColor appearance.stackedLayoutAppearance = itemAppearance appearance.inlineLayoutAppearance = itemAppearance appearance.compactInlineLayoutAppearance = itemAppearance tabBar.standardAppearance = appearance if #available(iOS 15.0, *) { tabBar.scrollEdgeAppearance = appearance } tabBar.backgroundColor = bgColor tabBar.isTranslucent = false The problem: The selected title/icon color works. The normal title color is ignored and stays white. This happens after moving to the newer tab bar appearance behavior / Liquid Glass environment. Question: Is there any additional configuration required for UITabBarAppearance so that the normal UITabBarItem title color is respected? Could unselectedItemTintColor, tintColor, scrollEdgeAppearance, or Liquid Glass behavior override normal.titleTextAttributes?
Replies
3
Boosts
0
Views
271
Activity
Jul ’26
UISceneDelegate migration - firm deadline?
I have not yet completed the migration to scene delegate. If I still build with Xcode 26, will my app continue to launch on iOS 27 even if I release updates (still built with Xcode 26) after the iOS 27 release?
Topic: UI Frameworks SubTopic: UIKit
Replies
4
Boosts
0
Views
454
Activity
Jul ’26
NSApp.activate() does not work with menu bar (background) apps
NSApp(ignoringOtherApps:) is deprecated but there is no other working alternative for menu bar apps. NSApp.activate() does not work when no app windows are active and we want to show a window from a menu bar application. Making it impossible for the app to open a window and make it active. Is it really an intended behavior? Here is a sample project showing the issue: https://github.com/wojciech-kulik/macos-menu-bar-bug Steps to reproduce: Run the app. Focus some other app like Finder or Safari. Click on the app's menu bar icon and select "Open". The app window will appear below the other app's window, instead of being brought to the front. NSApp(ignoringOtherApps: true) works as expected though. I also created a feedback ticket: FB23508310
Replies
10
Boosts
1
Views
387
Activity
Jul ’26
Why does SwiftUI not come with an Environment entry for the current NavigationPath?
If I have a detail view, it can include a NavigationLink (with either a specific destination view, or a value to be resolved by the nearest .navigationDestination handler in to a view). But some operations cannot be captured by a NavigationLink. For example, perhaps this detail view is editing a list, and I have a button to insert a new item. I may wish to insert the new item, and then navigate to a further editor for the inserted item. I can't do that with a NavigationLink: NavigationLink { // 🚨 This is a @ViewBuilder/@ContentBuilder, and there are no guarantees about how often it is invoked. let newItem = dataSource.insertNewItem() ItemEditor(newItem) } label: { // ... } This is the use-case which NavigationPath or typed navigation stacks handle for us: Button { let newItem = dataSource.insertNewItem() navigationPath.append(newItem) } label: { // ... } .navigationDestination(for: Item.self) { item in ItemEditor(item) } Unfortunately, while NavigationLink is able to inspect the View's environment, find the nearest NavigationStack, and push to it, there is no built-in @Environment key for programmatic navigation to do the same. Instead, developers need to add the path as an explicit state variable where the stack is declared, and manually pass it around or create their own @Environment keys, being diligent to ensure they always set that environment value in case some detail view happens to need to need programmatic navigation. I've never understood why. This seems to be a common problem in the ecosystem, and of course in UIKit you can always grab the nearest .navigationController, so I always thought it was an intentional omission. Was it? Should I file an enhancement request? Or is there a reason why this is not considered a good idea? Thanks
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
116
Activity
Jul ’26
SwiftUI 6 AttributeGraph warnings in console
On a MacBook Air M4 running macOS Sequoia 15.7.7, the following tiny code does warn inside the Xcode 26.3. Here is the whole console output: === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 110216 === === AttributeGraph: cycle detected through attribute 110216 === === AttributeGraph: cycle detected through attribute 110284 === === AttributeGraph: cycle detected through attribute 110284 === === AttributeGraph: cycle detected through attribute 110216 === === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 109592 === === AttributeGraph: cycle detected through attribute 110216 === Here is the full code: import SwiftUI @main struct myApp: App { var body: some Scene { WindowGroup { BaseView() } } } struct BaseView: View { @State private var isWorking: Bool = false var body: some View { Button("Go") { Task { // AttributeGraph warnings await MainActor.run { isWorking = true } await MainActor.run { isWorking = false } // No warnings at all // DispatchQueue.main.async { isWorking = true } // DispatchQueue.main.async { isWorking = false } } } .disabled(isWorking) .padding() } } You can see with DispatchQueue.main.async {...}, warnings aren't there. After a few days struggling with different AI support (Claude, ChatGPT, Perplexity), I didn't find any way to fix my own code. This tiny code is just there to show the issue. I tested multiple workarounds without finding one that fits to my app context. Thanks in advance for your support.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
4
Boosts
0
Views
219
Activity
Jul ’26