JUST ENDED
|

SwiftUI Q&A

Connect with Apple engineers in the SwiftUI Q&A on the Apple Developer Forums.

Post

Replies

Boosts

Views

Activity

AsyncRenderer stack limit
We've been getting stack overflows in code we don't control, in the background AsyncRenderer thread in a chain of calls to updateInheritedViewAsync. But the stack is less than 200 calls deep, presumably because it's a background thread with a smaller stack limit. Is it possible to adjust AsyncRenderer's stack limit? Or otherwise, what limits should we be aware of to prevent running into this issue? com.apple.SwiftUI.AsyncRenderer: EXC_BAD_ACCESS (code=2, address=0x16f5ebe30) #0 0x000000019c6b4460 in function signature specialization <Arg[3] = Dead> of static SwiftUI.DisplayList.ViewUpdater.Model.merge(item: inout SwiftUI.DisplayList.Item, index: SwiftUI.DisplayList.Index, into: inout SwiftUI.DisplayList.ViewUpdater.Model.State) -> SwiftUI.DisplayList.ViewUpdater.Model.MergedViewRequirements () #1 0x000000019c7c2850 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #2 0x000000019c7c3ef0 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #3 0x000000019c7c3ef0 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #4 0x000000019c7c3ef0 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () ... #147 0x000000019c7c364c in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #148 0x000000019c7c2074 in SwiftUI.DisplayList.ViewUpdater.updateAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldList: SwiftUI.DisplayList, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newList: SwiftUI.DisplayList, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #149 0x000000019c7c1a78 in renderAsync () #150 0x000000019c60fc68 in renderDisplayList () #151 0x000000019c612094 in protocol witness for SwiftUI.ViewGraphRenderHost.renderDisplayList(_: SwiftUI.DisplayList, asynchronously: Swift.Bool, time: SwiftUI.Time, nextTime: SwiftUI.Time, targetTimestamp: Swift.Optional<SwiftUI.Time>, version: SwiftUI.DisplayList.Version, maxVersion: SwiftUI.DisplayList.Version) -> SwiftUI.Time in conformance SwiftUI.ViewGraph : SwiftUI.ViewGraphRenderHost in SwiftUI () #152 0x000000019c7c0dd0 in renderAsync () #153 0x000000019c7be6c8 in SwiftUI.ViewGraphHost.displayLinkTimer(timestamp: SwiftUI.Time, targetTimestamp: SwiftUI.Time, isAsyncThread: Swift.Bool) -> () () #154 0x000000019c7beab8 in SwiftUI.ViewGraphDisplayLink.displayLinkTimer(__C.CADisplayLink) -> () () #155 0x000000019c7be5a8 in @objc SwiftUI.ViewGraphDisplayLink.displayLinkTimer(__C.CADisplayLink) -> () () #156 0x0000000192fdbb24 in CA::Display::DisplayLinkItem::dispatch_ () #157 0x0000000192fb9164 in CA::Display::DisplayLink::dispatch_items () #158 0x0000000192f91870 in display_timer_callback () #159 0x000000019256d4cc in __CFMachPortPerform () #160 0x000000019259d0b0 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ () #161 0x000000019259cfd8 in __CFRunLoopDoSource1 () #162 0x0000000192574c1c in __CFRunLoopRun () #163 0x0000000192573a6c in _CFRunLoopRunSpecificWithOptions () #164 0x0000000190533f54 in -[NSRunLoop(NSRunLoop) runMode:beforeDate:] () #165 0x000000018fb9a51c in -[NSRunLoop(NSRunLoop) run] () #166 0x000000019c7cd5b0 in function signature specialization <Arg[1] = Dead> of static SwiftUI.ViewGraphDisplayLink.asyncThread(arg: Swift.Optional<Any>) -> () () #167 0x000000019c7cd288 in @objc static SwiftUI.ViewGraphDisplayLink.asyncThread(arg: Swift.Optional<Any>) -> () () #168 0x000000018fbf321c in __NSThread__start__ () #169 0x00000001ef0d044c in _pthread_start ()
Topic: UI Frameworks SubTopic: SwiftUI
2
1
65
7h
Making View's init nonisolated with environment variables
Views with custom nonisolated init fail to compile when using @MainActor-isolated @Environment properties (e.g., \.openURL, \.dismiss). From the Swift 6 migration documentation, it seems encouraged to define inits nonisolated, and it seems base SwiftUI components also have their inits defined as nonisolated (e.g. TimelineView, LazyHStack, etc), which makes sense. How do you achieve marking a SwiftUI View's init as nonisolated when it uses environment variables, without producing the following build error "Main actor-isolated default value of 'self.openURL' cannot be used in a nonisolated initalizer" ? It seems @State variable defined in a view has the ability to be set in a nonisolated init but not @Environment. What mechanism prevents this under the hood ?
Topic: UI Frameworks SubTopic: SwiftUI
7
0
82
8h
How to get the glassy picker showed at WWD27
In the session "What’s new in SwiftUI", at 02:38 Steven shows various Liquid Glass components, among them, a very pretty interactive glassy Picker. At first I thought this was built into the system and tried everything possible, until to rewatch the presentation and notice this: "On macOS, like on iOS, you can mark Liquid Glass custom elements as "interactive" so they respond more fluidly to user's clicks. And this is optimized to work great with the mouse pointer, so it feels right at home on the Mac." Does anyone have pointers to where one can find a Picker that implements all these system behaviors that folks have come to expect? I have my own version, which is deeply lacking, and so is every other implementation out there that I saw, and I thought sprinkling some "interactive" as instructed would help, but it barely made a dent.
Topic: UI Frameworks SubTopic: SwiftUI
2
0
83
9h
Dynamic layouts with multi-line Text views
For a dynamic layout reacting to width changes using ViewThatFits, I need a 2-line Text view where content gets wrapped exactly once, but doesn't get abbreviated. If the text is too long to fit in two lines, ViewThatFits should choose the next layout. I tried to use .lineLimit(2, reservesSpace: true), but then ViewThatFits always takes this layout even when the text content gets too long to fit, so it gets abbreviated with "...", instead of choosing the next layout. How else can I build a layout with a two-line Text, which does signal to ViewThatFits if the space doesn't fit the entire text so it can choose the next layout?
Topic: UI Frameworks SubTopic: SwiftUI
2
0
52
10h
How to avoid trailing toolbar item re-rendering on child navigation
I have a NavigationStack where every child view except the root has a trailing close button. On each child view transition, the button re-renders itself. Is there a way to fix the button? I saw in the Apple Developer app the behavior I want when registering a lab and the confirmation screen, but I think the implementation is just changing the center content of the view and it isn't pushing a new view to the stack path that has different toolbar items. Root: VStack { Content Next button --> Page 2 } Cancel button leading edge Page 2: VStack { Copy Next button --> page 3 } built in back button leading edge cancel button trailing edge Page 3: VStack { Copy Finish button --> dismisses whole workflow } built in back button leading edge cancel button trailing edge So on page 3, the cancel button is new. I can't figure out how to not have the glass effect animate it in new. I want the 'same' cancel button to be there. This is an oversimplification of a resumable form where the user can cancel (save and resume) at any time. Is there a built in way to have the trailing edge button be fixed? Would moving where the button is defined make a different and expose a way for each child view to propagate upwards if the cancel button should be shown or not? Updated with sample, assumes iOS 18 + 26 code so using .topTrailing not new 'action' placement: import SwiftUI struct Demo: View { @State private var path: [String] = [] var body: some View { NavigationStack(path: $path) { Button("Go") { path.append("Second") } .navigationDestination(for: String.self) { destination in switch destination { case "Second": VStack { Text("Second") Button("Next") { path.append("Third") } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", role: .cancel) { path = [] } } } case "Third": VStack { Text("Third") Button("Finish") { path = [] } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", role: .cancel) { path = [] } } } default: Text("Undefined") } } } } }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
37
10h
NSViewRepresentable updates triggered by .onChange ignore SwiftUI Transactions on macOS
I am encountering a systemic issue on macOS where NSViewRepresentable (and some native container views like Table) completely discard explicit SwiftUI animations when the state change is handled via an .onChange modifier. While the exact same reactive architecture produces fluid animations on iOS, the AppKit bridge on macOS snaps the frame updates instantly. I have filed a formal bug report for this behavior, but I want to open this up to the community to see if anyone has found a cleaner architectural workaround. The Problem When observing a state change (e.g., via @AppStorage, @SceneStorage, or local state) using .onChange, applying a withAnimation block fails to animate the underlying layer changes in an AppKit representable view. // The Reactive Pattern that breaks on macOS .onChange(of: toggle) { newValue in withAnimation(.easeInOut(duration: 0.5)) { self.targetColor = newValue ? .systemBlue : .systemRed } } The Diagnostic Anomaly If you inspect context.transaction inside the updateNSView(_:context:) method during this lifecycle pass, SwiftUI reports that the transaction is animated: func updateNSView(_ nsView: NSView, context: Context) { // Prints 'true', indicating SwiftUI thinks it's animating print("Is Animated: \(context.transaction.animation != nil)") // Result: Snaps instantly. No animation occurs. nsView.layer?.backgroundColor = targetColor.cgColor } Why It Happens (The Double-Commit) It appears that on macOS, .onChange flushes a static layout transaction to the window layer immediately upon the state mutating. By the time the withAnimation block evaluates inside the closure, the AppKit backing layer has already processed a implicit setDisableActions(true) directive. The GPU pipeline for that transaction frame is effectively closed, despite what the context.transaction metadata claims. The Low-Level Workaround To force the AppKit bridge to respect the animation intent, I have to manually drop into Core Animation inside updateNSView and explicitly veto SwiftUI's action-disabling behavior: func updateNSView(_ nsView: NSView, context: Context) { CATransaction.begin() if context.transaction.animation != nil { // Explicitly override SwiftUI's implicit frame lock CATransaction.setDisableActions(false) CATransaction.setAnimationDuration(0.5) // Hardcoded fallback match } else { CATransaction.setDisableActions(true) } nsView.layer?.backgroundColor = targetColor.cgColor CATransaction.commit() } My Questions: Is this intentional behavior due to how AppKit's layer-backed architectures handle frame integrity vs. iOS's fluid layout engine? Has anyone found a way to bridge SwiftUI's Animation type curves (like .spring()) cleanly down into the CATransaction or NSAnimationContext layer without hardcoding durations inside updateNSView? Is there a purely "Reactive" paradigm that avoids mutating state at the primary action source (e.g., forcing a Button to own the animation logic) while maintaining fluid transitions on macOS?
Topic: UI Frameworks SubTopic: SwiftUI
1
0
40
10h
ForEach with calculations between each cell
I'm attempting to add a TimeInterval calculated at each step of a ForEach to a Date (hr & min) of the previous cell. For each cell this works: Start Time = 12:55 Delta interval = 3600 seconds (1hr) Next time = 1:55 I want to use that Next time as the start one for the next cell - instead what I have working is Delta interval = 30 (5 min) Next time = 1:00 but what I want is 2:00 (12:55 + 1hr + 5min) I'm just having trouble thinking through how to do that. Thanks!
Topic: UI Frameworks SubTopic: SwiftUI
2
0
33
10h
Custom PinnedScrollableViews
In a simple scenario, it's possible to have a ScrollView that contains a LazyVStack where the headers or footers of Section gets pinned to the top safe area. In a more complicated scenario, where The ScrollView needs to ignore the top safe area The navigation bar is hidden until a certain view, call it Foo, has gone behind what used to be the top safe area, i.e., only about 100p of the view is visible which would be invisible if the navigation bar wasn't transparent/hidden. The navigation bar becomes visible once Foo is scrolled up to a threshold that was explained earlier A second view, call is Bar, that's positioned below Foo, should never go behind the navigation bar, i.e., it should be pinned to the bottom of the navigation bar I managed to achieve this behaviour by having a State for the ignored safe area edges that gets updated based on how far Foo is scrolled. However, I get a jumpy behaviour because the ScrollView tries to adjust its contentOffset/contentInset based on the new top safe area. This jumpy behaviour is very hard to compensate especially when user scrolls very fast. In UIKit, I could achieve this behaviour by overriding viewSafeAreaInsetsDidChangeand tweaking the contentInset, and contentOffset on a collection/table view. Maybe I need to rethink my approach in a declarative way that aligns better with SwiftUI. Any thoughts on how to achieve this?
Topic: UI Frameworks SubTopic: SwiftUI
4
1
52
10h
iOS 27 automatic resize
With iOS 27's automatic resizability for iPhone apps on iPad and in iPhone Mirroring, what's the recommended pattern for views that need genuinely different layouts at different size classes — is ViewThatFits the intended tool, or should we still branch on size class for larger structural changes? — Divya Ravi, Senior iOS Engineer
Topic: UI Frameworks SubTopic: SwiftUI
2
2
86
10h
List selection (UI) does not update when selection is changed programmatically
I have a List that's embedded in an NSHostingView with an @Observable data connecting the two worlds. I can select an item in the list with the mouse and use arrow keys to change the selection and it is updated properly on the AppKit side. However, when I change the selection from the AppKit side, the selection disappears in the List, even though an .onChange does get triggered with the right new selection ID. But the UI no longer displays it. I created a simple NSHostView example and that works. But the same method does not work in a more complex layout where the view is much deeper in the hierarchy. Something is happening because the List loses its last selection highlight. What's the best approach to tracking down why the List UI is not updating the selection? I am trying to avoid going back to using NSTableView and doing it all manually, but I really need to selection to be able to change. Thank you.
Topic: UI Frameworks SubTopic: SwiftUI
1
0
20
10h
Guidance for Custom View Styles
If I want to implement the "view style" pattern that various SwiftUI components have (like ButtonStyle for Button and PickerStyle for Picker, to name a few) for my own custom components, is there any guidance on how to do that? Specifically, is there a way to do that without having to resort to using AnyView? My attempts to implement this have been fine with retaining type information using some View and generics, up until the point I need to create an interface for specifying a view style to use and propagating that down to the component that I'm styling. Using the SwiftUI environment seems like the natural way to do this propagation, but I seem to run afoul of the type system when trying to use it. If we take ButtonStyle from SwiftUI as an example of the general structure of this pattern, we're talking about having a protocol with an associated Body type, and a corresponding makeBody function that does the actual styling of the component and returns a Body instance. Because of the associated types in this protocol, I'm unsure how to put an instance of something that conforms to the protocol into the environment for propagation. I end up having to create a "sibling" type of sorts that more or less does the same thing as my protocol, but works with AnyView so I can have concrete types to use with the environment and pass around to my view. This doesn't seem ideal because of the use of AnyView and some of the downsides that come with that. I've included a simplified version of this at the end of this post to showcase roughly what I'm doing now that is working, but it feels like there should be some better way to achieve this without needing to reach for AnyView. Is there something that I'm not aware of with Swift or SwiftUI that would let me ditch it, or is this the best way to achieve this right now without improvements to SwiftUI to better support this? protocol MyViewStyle { associatedtype Body: View func makeBody(text: String) -> Body } struct TextMyViewStyle: MyViewStyle { func makeBody(text: String) -> some View { return Text(text) } } struct AnyMyViewStyle { let _makeBody: (String) -> AnyView init<Style: MyViewStyle>(_ style: Style) { self._makeBody = { text in AnyView(style.makeBody(text: text)) } } func makeBody(text: String) -> AnyView { _makeBody(text) } } extension EnvironmentValues { @Entry var myViewStyle: AnyMyViewStyle = AnyMyViewStyle(TextMyViewStyle()) } struct MyView: View { @Environment(\.myViewStyle) private var style let text: String var body: some View { style.makeBody(text: text) } }
Topic: UI Frameworks SubTopic: SwiftUI
1
2
49
10h
Supporting iOS15 with widgets & CoreData
I have an app where CoreData is working great - but I want to add widgets. I'm following a tutorial where they create an AppGroup and in the migration they use appendingPathComponent(_:) which is deprecated (iOS 8.0–26.1) however the recommended replacement appending(path:directoryHint:) starts support at iOS 16. I'm hanging on to iOS 15 for some users who don't want to upgrade their phones - but is it time to give up on that for widgets running on released iOS 26 and beyond? I assume I'll need to use if #available(iOS 16.0, *) for the new code. How does this work for the CoreData migration for the older phones? So far this is just in TestFlight. Any recommendations?
Topic: UI Frameworks SubTopic: SwiftUI
1
0
27
10h
How to Sandbox SwiftData Edits in .sheet
Is this the right way to pass data to a sheet for editing? struct Detail: View { ... // The single atomic source of truth for our sheet presentation @State var editorConfig: EditorConfig? // Completely encapsulated local configuration package struct EditorConfig: Identifiable { var id: PersistentIdentifier { item.persistentModelID } let context: ModelContext let item: Item } var body: some View { ... Button("Edit") { // 1. Spin up a separate scratchpad container layer let context = ModelContext(modelContext.container) context.autosaveEnabled = false // 2. Safely resolve our model inside the new isolated playground if let sandboxItem = context.model(for: item.persistentModelID) as? Item { // 3. Package it up to trigger the sheet presentation editorConfig = EditorConfig(context: context, item: sandboxItem) } } } } // 4. SwiftUI tracks value replacement accurately without ghost state bugs .sheet(item: $editorConfig) { config in // Inject the isolated context into the sheet's environment chain EditorView(item: config.item) .environment(\.modelContext, config.context) } } }
Topic: UI Frameworks SubTopic: SwiftUI
1
1
32
10h
Official guidance and documentation for creating reusable components and design systems
I'm heavily involved in making reusable components for specific features, as well as generic ones as part of a design system / component library. Does Apple have any guidance doing this? There is a lot to be learned from the decisions around the 'style' APIs, as well as the overloaded constrained initializers of views like Label. The design system should be opinionated, but allow a degree of flexibility. I liked Sarah's talk about incorporating brand which is certainly important when building components for 10+ apps, internal and external. The focus on purposeful design, but there isn't much at a technical level for designing (coding) reusable components and embracing strategies using the Environment, making custom EnvironmentValues, leveraging built-in system constructs, etc. Any resources and guidance here would be welcomed!
Topic: UI Frameworks SubTopic: SwiftUI
1
1
61
11h
NavigationSplitView background configuration
When I last tried configuring NavigationSplitView about a year ago, it was hard or impossible to configure background. Setting a custom or clear background was not supported, and NavigationSplitViewStyle seemingly did not support custom implementations. Has this been improved?
Topic: UI Frameworks SubTopic: SwiftUI
1
0
21
11h
Improving List performance with DisclosureGroup in large data sets
I have been pleased to see SwiftUI’s List performance improve over the years. However, when using a List that contains DisclosureGroup views, expanding and collapsing items becomes significantly slower as the amount of data grows. In my case, I need to control the initial expanded/collapsed state of each disclosure item, so I cannot use the recursive List(_:children:) API. Is there a recommended way to improve the performance of a List containing DisclosureGroup views, or is falling back to AppKit’s NSOutlineView currently the only practical solution? (Yes, for context, my app is for macOS.) The following code shows the relevant portion of my implementation: List(self.summary.files, selection: $selection) { file in DisclosureGroup(isExpanded: $expandedFileURLs.contains(file.id)) { ForEach(file.matches) { match in FolderFindMatchView(match: match) .tag(FolderFind.ResultID.match(fileID: file.id, matchID: match.id)) } } label: { FolderFindFileResultView(file: file) .draggable(item: FolderFindDraggedFile(id: .file(file.id), fileURL: file.fileURL)) } .listRowSeparator(.hidden) .tag(FolderFind.ResultID.file(file.id)) }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
46
11h
White background in UIHostingController
Good morning! Our app is currently a mix of UIKit and SwiftUI. All new code is SwiftUI and we’re gradually replacing old code but for now we have SwiftUI views in UIHostingControllers where needed. Our app is a dark color scheme regardless of the device light/dark setting. One issue we’ve have is that some view in the hierarchy of the UIHostingController seems to have a white background. This is not normally visible, but when sliding views on and off in navigation, there’s a hint of white showing at the edge of the view as it moves. It’s subtle but users have noticed. I thought I filed this bug some time ago but I can’t find it. Just wondering if you’re aware and if there’s any update.
Topic: UI Frameworks SubTopic: SwiftUI
1
0
25
11h
AsyncRenderer stack limit
We've been getting stack overflows in code we don't control, in the background AsyncRenderer thread in a chain of calls to updateInheritedViewAsync. But the stack is less than 200 calls deep, presumably because it's a background thread with a smaller stack limit. Is it possible to adjust AsyncRenderer's stack limit? Or otherwise, what limits should we be aware of to prevent running into this issue? com.apple.SwiftUI.AsyncRenderer: EXC_BAD_ACCESS (code=2, address=0x16f5ebe30) #0 0x000000019c6b4460 in function signature specialization <Arg[3] = Dead> of static SwiftUI.DisplayList.ViewUpdater.Model.merge(item: inout SwiftUI.DisplayList.Item, index: SwiftUI.DisplayList.Index, into: inout SwiftUI.DisplayList.ViewUpdater.Model.State) -> SwiftUI.DisplayList.ViewUpdater.Model.MergedViewRequirements () #1 0x000000019c7c2850 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #2 0x000000019c7c3ef0 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #3 0x000000019c7c3ef0 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #4 0x000000019c7c3ef0 in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () ... #147 0x000000019c7c364c in SwiftUI.DisplayList.ViewUpdater.updateInheritedViewAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldItem: SwiftUI.DisplayList.Item, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newItem: SwiftUI.DisplayList.Item, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #148 0x000000019c7c2074 in SwiftUI.DisplayList.ViewUpdater.updateAsync(platform: SwiftUI.DisplayList.ViewUpdater.Platform, oldList: SwiftUI.DisplayList, oldParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>, newList: SwiftUI.DisplayList, newParentState: Swift.UnsafePointer<SwiftUI.DisplayList.ViewUpdater.Model.State>) -> Swift.Optional<SwiftUI.Time> () #149 0x000000019c7c1a78 in renderAsync () #150 0x000000019c60fc68 in renderDisplayList () #151 0x000000019c612094 in protocol witness for SwiftUI.ViewGraphRenderHost.renderDisplayList(_: SwiftUI.DisplayList, asynchronously: Swift.Bool, time: SwiftUI.Time, nextTime: SwiftUI.Time, targetTimestamp: Swift.Optional<SwiftUI.Time>, version: SwiftUI.DisplayList.Version, maxVersion: SwiftUI.DisplayList.Version) -> SwiftUI.Time in conformance SwiftUI.ViewGraph : SwiftUI.ViewGraphRenderHost in SwiftUI () #152 0x000000019c7c0dd0 in renderAsync () #153 0x000000019c7be6c8 in SwiftUI.ViewGraphHost.displayLinkTimer(timestamp: SwiftUI.Time, targetTimestamp: SwiftUI.Time, isAsyncThread: Swift.Bool) -> () () #154 0x000000019c7beab8 in SwiftUI.ViewGraphDisplayLink.displayLinkTimer(__C.CADisplayLink) -> () () #155 0x000000019c7be5a8 in @objc SwiftUI.ViewGraphDisplayLink.displayLinkTimer(__C.CADisplayLink) -> () () #156 0x0000000192fdbb24 in CA::Display::DisplayLinkItem::dispatch_ () #157 0x0000000192fb9164 in CA::Display::DisplayLink::dispatch_items () #158 0x0000000192f91870 in display_timer_callback () #159 0x000000019256d4cc in __CFMachPortPerform () #160 0x000000019259d0b0 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ () #161 0x000000019259cfd8 in __CFRunLoopDoSource1 () #162 0x0000000192574c1c in __CFRunLoopRun () #163 0x0000000192573a6c in _CFRunLoopRunSpecificWithOptions () #164 0x0000000190533f54 in -[NSRunLoop(NSRunLoop) runMode:beforeDate:] () #165 0x000000018fb9a51c in -[NSRunLoop(NSRunLoop) run] () #166 0x000000019c7cd5b0 in function signature specialization <Arg[1] = Dead> of static SwiftUI.ViewGraphDisplayLink.asyncThread(arg: Swift.Optional<Any>) -> () () #167 0x000000019c7cd288 in @objc static SwiftUI.ViewGraphDisplayLink.asyncThread(arg: Swift.Optional<Any>) -> () () #168 0x000000018fbf321c in __NSThread__start__ () #169 0x00000001ef0d044c in _pthread_start ()
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
1
Views
65
Activity
7h
Making View's init nonisolated with environment variables
Views with custom nonisolated init fail to compile when using @MainActor-isolated @Environment properties (e.g., \.openURL, \.dismiss). From the Swift 6 migration documentation, it seems encouraged to define inits nonisolated, and it seems base SwiftUI components also have their inits defined as nonisolated (e.g. TimelineView, LazyHStack, etc), which makes sense. How do you achieve marking a SwiftUI View's init as nonisolated when it uses environment variables, without producing the following build error "Main actor-isolated default value of 'self.openURL' cannot be used in a nonisolated initalizer" ? It seems @State variable defined in a view has the ability to be set in a nonisolated init but not @Environment. What mechanism prevents this under the hood ?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
7
Boosts
0
Views
82
Activity
8h
How to get the glassy picker showed at WWD27
In the session "What’s new in SwiftUI", at 02:38 Steven shows various Liquid Glass components, among them, a very pretty interactive glassy Picker. At first I thought this was built into the system and tried everything possible, until to rewatch the presentation and notice this: "On macOS, like on iOS, you can mark Liquid Glass custom elements as "interactive" so they respond more fluidly to user's clicks. And this is optimized to work great with the mouse pointer, so it feels right at home on the Mac." Does anyone have pointers to where one can find a Picker that implements all these system behaviors that folks have come to expect? I have my own version, which is deeply lacking, and so is every other implementation out there that I saw, and I thought sprinkling some "interactive" as instructed would help, but it barely made a dent.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
83
Activity
9h
Dynamic layouts with multi-line Text views
For a dynamic layout reacting to width changes using ViewThatFits, I need a 2-line Text view where content gets wrapped exactly once, but doesn't get abbreviated. If the text is too long to fit in two lines, ViewThatFits should choose the next layout. I tried to use .lineLimit(2, reservesSpace: true), but then ViewThatFits always takes this layout even when the text content gets too long to fit, so it gets abbreviated with "...", instead of choosing the next layout. How else can I build a layout with a two-line Text, which does signal to ViewThatFits if the space doesn't fit the entire text so it can choose the next layout?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
52
Activity
10h
How to avoid trailing toolbar item re-rendering on child navigation
I have a NavigationStack where every child view except the root has a trailing close button. On each child view transition, the button re-renders itself. Is there a way to fix the button? I saw in the Apple Developer app the behavior I want when registering a lab and the confirmation screen, but I think the implementation is just changing the center content of the view and it isn't pushing a new view to the stack path that has different toolbar items. Root: VStack { Content Next button --> Page 2 } Cancel button leading edge Page 2: VStack { Copy Next button --> page 3 } built in back button leading edge cancel button trailing edge Page 3: VStack { Copy Finish button --> dismisses whole workflow } built in back button leading edge cancel button trailing edge So on page 3, the cancel button is new. I can't figure out how to not have the glass effect animate it in new. I want the 'same' cancel button to be there. This is an oversimplification of a resumable form where the user can cancel (save and resume) at any time. Is there a built in way to have the trailing edge button be fixed? Would moving where the button is defined make a different and expose a way for each child view to propagate upwards if the cancel button should be shown or not? Updated with sample, assumes iOS 18 + 26 code so using .topTrailing not new 'action' placement: import SwiftUI struct Demo: View { @State private var path: [String] = [] var body: some View { NavigationStack(path: $path) { Button("Go") { path.append("Second") } .navigationDestination(for: String.self) { destination in switch destination { case "Second": VStack { Text("Second") Button("Next") { path.append("Third") } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", role: .cancel) { path = [] } } } case "Third": VStack { Text("Third") Button("Finish") { path = [] } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Close", role: .cancel) { path = [] } } } default: Text("Undefined") } } } } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
37
Activity
10h
NSViewRepresentable updates triggered by .onChange ignore SwiftUI Transactions on macOS
I am encountering a systemic issue on macOS where NSViewRepresentable (and some native container views like Table) completely discard explicit SwiftUI animations when the state change is handled via an .onChange modifier. While the exact same reactive architecture produces fluid animations on iOS, the AppKit bridge on macOS snaps the frame updates instantly. I have filed a formal bug report for this behavior, but I want to open this up to the community to see if anyone has found a cleaner architectural workaround. The Problem When observing a state change (e.g., via @AppStorage, @SceneStorage, or local state) using .onChange, applying a withAnimation block fails to animate the underlying layer changes in an AppKit representable view. // The Reactive Pattern that breaks on macOS .onChange(of: toggle) { newValue in withAnimation(.easeInOut(duration: 0.5)) { self.targetColor = newValue ? .systemBlue : .systemRed } } The Diagnostic Anomaly If you inspect context.transaction inside the updateNSView(_:context:) method during this lifecycle pass, SwiftUI reports that the transaction is animated: func updateNSView(_ nsView: NSView, context: Context) { // Prints 'true', indicating SwiftUI thinks it's animating print("Is Animated: \(context.transaction.animation != nil)") // Result: Snaps instantly. No animation occurs. nsView.layer?.backgroundColor = targetColor.cgColor } Why It Happens (The Double-Commit) It appears that on macOS, .onChange flushes a static layout transaction to the window layer immediately upon the state mutating. By the time the withAnimation block evaluates inside the closure, the AppKit backing layer has already processed a implicit setDisableActions(true) directive. The GPU pipeline for that transaction frame is effectively closed, despite what the context.transaction metadata claims. The Low-Level Workaround To force the AppKit bridge to respect the animation intent, I have to manually drop into Core Animation inside updateNSView and explicitly veto SwiftUI's action-disabling behavior: func updateNSView(_ nsView: NSView, context: Context) { CATransaction.begin() if context.transaction.animation != nil { // Explicitly override SwiftUI's implicit frame lock CATransaction.setDisableActions(false) CATransaction.setAnimationDuration(0.5) // Hardcoded fallback match } else { CATransaction.setDisableActions(true) } nsView.layer?.backgroundColor = targetColor.cgColor CATransaction.commit() } My Questions: Is this intentional behavior due to how AppKit's layer-backed architectures handle frame integrity vs. iOS's fluid layout engine? Has anyone found a way to bridge SwiftUI's Animation type curves (like .spring()) cleanly down into the CATransaction or NSAnimationContext layer without hardcoding durations inside updateNSView? Is there a purely "Reactive" paradigm that avoids mutating state at the primary action source (e.g., forcing a Button to own the animation logic) while maintaining fluid transitions on macOS?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
40
Activity
10h
ForEach with calculations between each cell
I'm attempting to add a TimeInterval calculated at each step of a ForEach to a Date (hr & min) of the previous cell. For each cell this works: Start Time = 12:55 Delta interval = 3600 seconds (1hr) Next time = 1:55 I want to use that Next time as the start one for the next cell - instead what I have working is Delta interval = 30 (5 min) Next time = 1:00 but what I want is 2:00 (12:55 + 1hr + 5min) I'm just having trouble thinking through how to do that. Thanks!
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
33
Activity
10h
Custom PinnedScrollableViews
In a simple scenario, it's possible to have a ScrollView that contains a LazyVStack where the headers or footers of Section gets pinned to the top safe area. In a more complicated scenario, where The ScrollView needs to ignore the top safe area The navigation bar is hidden until a certain view, call it Foo, has gone behind what used to be the top safe area, i.e., only about 100p of the view is visible which would be invisible if the navigation bar wasn't transparent/hidden. The navigation bar becomes visible once Foo is scrolled up to a threshold that was explained earlier A second view, call is Bar, that's positioned below Foo, should never go behind the navigation bar, i.e., it should be pinned to the bottom of the navigation bar I managed to achieve this behaviour by having a State for the ignored safe area edges that gets updated based on how far Foo is scrolled. However, I get a jumpy behaviour because the ScrollView tries to adjust its contentOffset/contentInset based on the new top safe area. This jumpy behaviour is very hard to compensate especially when user scrolls very fast. In UIKit, I could achieve this behaviour by overriding viewSafeAreaInsetsDidChangeand tweaking the contentInset, and contentOffset on a collection/table view. Maybe I need to rethink my approach in a declarative way that aligns better with SwiftUI. Any thoughts on how to achieve this?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
4
Boosts
1
Views
52
Activity
10h
Intermixing Navigation with SwiftUI and UIKit
I've been adopting SwiftUI into a legacy UIKit app. Individual views work great, but when I try to intermix SwiftUI and UIKit navigation things go bad fast. What is the best practice here?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
80
Activity
10h
Performance considerations using ViewThatFits
ViewThatFits is a great way to handle large type and resizability. I wonder what are the performance considerations here? What are common pitfalls using it? I appreciate any tip or thing to keep in mind. ✌️
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
1
Views
62
Activity
10h
iOS 27 automatic resize
With iOS 27's automatic resizability for iPhone apps on iPad and in iPhone Mirroring, what's the recommended pattern for views that need genuinely different layouts at different size classes — is ViewThatFits the intended tool, or should we still branch on size class for larger structural changes? — Divya Ravi, Senior iOS Engineer
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
2
Views
86
Activity
10h
List selection (UI) does not update when selection is changed programmatically
I have a List that's embedded in an NSHostingView with an @Observable data connecting the two worlds. I can select an item in the list with the mouse and use arrow keys to change the selection and it is updated properly on the AppKit side. However, when I change the selection from the AppKit side, the selection disappears in the List, even though an .onChange does get triggered with the right new selection ID. But the UI no longer displays it. I created a simple NSHostView example and that works. But the same method does not work in a more complex layout where the view is much deeper in the hierarchy. Something is happening because the List loses its last selection highlight. What's the best approach to tracking down why the List UI is not updating the selection? I am trying to avoid going back to using NSTableView and doing it all manually, but I really need to selection to be able to change. Thank you.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
20
Activity
10h
Inspector built-in navigation bar missed in iOS26
The inspector attached to the multi-column Split View, does not display its navigation elements on iOS 26. How to fix it?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
5
Boosts
0
Views
50
Activity
10h
Guidance for Custom View Styles
If I want to implement the "view style" pattern that various SwiftUI components have (like ButtonStyle for Button and PickerStyle for Picker, to name a few) for my own custom components, is there any guidance on how to do that? Specifically, is there a way to do that without having to resort to using AnyView? My attempts to implement this have been fine with retaining type information using some View and generics, up until the point I need to create an interface for specifying a view style to use and propagating that down to the component that I'm styling. Using the SwiftUI environment seems like the natural way to do this propagation, but I seem to run afoul of the type system when trying to use it. If we take ButtonStyle from SwiftUI as an example of the general structure of this pattern, we're talking about having a protocol with an associated Body type, and a corresponding makeBody function that does the actual styling of the component and returns a Body instance. Because of the associated types in this protocol, I'm unsure how to put an instance of something that conforms to the protocol into the environment for propagation. I end up having to create a "sibling" type of sorts that more or less does the same thing as my protocol, but works with AnyView so I can have concrete types to use with the environment and pass around to my view. This doesn't seem ideal because of the use of AnyView and some of the downsides that come with that. I've included a simplified version of this at the end of this post to showcase roughly what I'm doing now that is working, but it feels like there should be some better way to achieve this without needing to reach for AnyView. Is there something that I'm not aware of with Swift or SwiftUI that would let me ditch it, or is this the best way to achieve this right now without improvements to SwiftUI to better support this? protocol MyViewStyle { associatedtype Body: View func makeBody(text: String) -> Body } struct TextMyViewStyle: MyViewStyle { func makeBody(text: String) -> some View { return Text(text) } } struct AnyMyViewStyle { let _makeBody: (String) -> AnyView init<Style: MyViewStyle>(_ style: Style) { self._makeBody = { text in AnyView(style.makeBody(text: text)) } } func makeBody(text: String) -> AnyView { _makeBody(text) } } extension EnvironmentValues { @Entry var myViewStyle: AnyMyViewStyle = AnyMyViewStyle(TextMyViewStyle()) } struct MyView: View { @Environment(\.myViewStyle) private var style let text: String var body: some View { style.makeBody(text: text) } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
2
Views
49
Activity
10h
Supporting iOS15 with widgets & CoreData
I have an app where CoreData is working great - but I want to add widgets. I'm following a tutorial where they create an AppGroup and in the migration they use appendingPathComponent(_:) which is deprecated (iOS 8.0–26.1) however the recommended replacement appending(path:directoryHint:) starts support at iOS 16. I'm hanging on to iOS 15 for some users who don't want to upgrade their phones - but is it time to give up on that for widgets running on released iOS 26 and beyond? I assume I'll need to use if #available(iOS 16.0, *) for the new code. How does this work for the CoreData migration for the older phones? So far this is just in TestFlight. Any recommendations?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
27
Activity
10h
How to Sandbox SwiftData Edits in .sheet
Is this the right way to pass data to a sheet for editing? struct Detail: View { ... // The single atomic source of truth for our sheet presentation @State var editorConfig: EditorConfig? // Completely encapsulated local configuration package struct EditorConfig: Identifiable { var id: PersistentIdentifier { item.persistentModelID } let context: ModelContext let item: Item } var body: some View { ... Button("Edit") { // 1. Spin up a separate scratchpad container layer let context = ModelContext(modelContext.container) context.autosaveEnabled = false // 2. Safely resolve our model inside the new isolated playground if let sandboxItem = context.model(for: item.persistentModelID) as? Item { // 3. Package it up to trigger the sheet presentation editorConfig = EditorConfig(context: context, item: sandboxItem) } } } } // 4. SwiftUI tracks value replacement accurately without ghost state bugs .sheet(item: $editorConfig) { config in // Inject the isolated context into the sheet's environment chain EditorView(item: config.item) .environment(\.modelContext, config.context) } } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
1
Views
32
Activity
10h
Official guidance and documentation for creating reusable components and design systems
I'm heavily involved in making reusable components for specific features, as well as generic ones as part of a design system / component library. Does Apple have any guidance doing this? There is a lot to be learned from the decisions around the 'style' APIs, as well as the overloaded constrained initializers of views like Label. The design system should be opinionated, but allow a degree of flexibility. I liked Sarah's talk about incorporating brand which is certainly important when building components for 10+ apps, internal and external. The focus on purposeful design, but there isn't much at a technical level for designing (coding) reusable components and embracing strategies using the Environment, making custom EnvironmentValues, leveraging built-in system constructs, etc. Any resources and guidance here would be welcomed!
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
1
Views
61
Activity
11h
NavigationSplitView background configuration
When I last tried configuring NavigationSplitView about a year ago, it was hard or impossible to configure background. Setting a custom or clear background was not supported, and NavigationSplitViewStyle seemingly did not support custom implementations. Has this been improved?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
21
Activity
11h
Improving List performance with DisclosureGroup in large data sets
I have been pleased to see SwiftUI’s List performance improve over the years. However, when using a List that contains DisclosureGroup views, expanding and collapsing items becomes significantly slower as the amount of data grows. In my case, I need to control the initial expanded/collapsed state of each disclosure item, so I cannot use the recursive List(_:children:) API. Is there a recommended way to improve the performance of a List containing DisclosureGroup views, or is falling back to AppKit’s NSOutlineView currently the only practical solution? (Yes, for context, my app is for macOS.) The following code shows the relevant portion of my implementation: List(self.summary.files, selection: $selection) { file in DisclosureGroup(isExpanded: $expandedFileURLs.contains(file.id)) { ForEach(file.matches) { match in FolderFindMatchView(match: match) .tag(FolderFind.ResultID.match(fileID: file.id, matchID: match.id)) } } label: { FolderFindFileResultView(file: file) .draggable(item: FolderFindDraggedFile(id: .file(file.id), fileURL: file.fileURL)) } .listRowSeparator(.hidden) .tag(FolderFind.ResultID.file(file.id)) }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
46
Activity
11h
White background in UIHostingController
Good morning! Our app is currently a mix of UIKit and SwiftUI. All new code is SwiftUI and we’re gradually replacing old code but for now we have SwiftUI views in UIHostingControllers where needed. Our app is a dark color scheme regardless of the device light/dark setting. One issue we’ve have is that some view in the hierarchy of the UIHostingController seems to have a white background. This is not normally visible, but when sliding views on and off in navigation, there’s a hint of white showing at the edge of the view as it moves. It’s subtle but users have noticed. I thought I filed this bug some time ago but I can’t find it. Just wondering if you’re aware and if there’s any update.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
25
Activity
11h