Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

Posts under SwiftUI tag

200 Posts

Post

Replies

Boosts

Views

Activity

SwiftUI List: observable reference types not deallocated immediately after refresh
Hello 👋 I ran into a SwiftUI lifecycle gotcha while debugging a List with .refreshable I share the code used to reproduce the issue @Observable final class CounterModel: Identifiable { let id: String var title: String var value: Int init(id: String, title: String, value: Int = 0) { self.id = id self.title = title self.value = value } deinit { print("deinit", title) } } @Observable final class ObservableCountersStore { var counters: [CounterModel] = [ .init(id: "1", title: "A"), .init(id: "2", title: "B"), .init(id: "3", title: "C") ] func refresh() async { try? await Task.sleep(nanoseconds: 300_000_000) counters = [.init(id: "4", title: "D")] } } struct ObservableCountersListView: View { @State private var store = ObservableCountersStore() var body: some View { List { ForEach(store.counters) { counter in ObservableCounterRow(counter: counter) } } .refreshable { await store.refresh() } } } struct ObservableCounterRow: View { let counter: CounterModel var body: some View { Text(counter.title) } } Observation: After calling refresh(), only some of the previous CounterModel only one CounterModel is deallocated immediately. Others are retained This doesn’t look like a leak, but it made me realize that passing observable reference types directly into List rows leads to non-deterministic object lifetimes, especially with .refreshable. Posting this as a gotcha — curious if this matches intended behavior or if others have run into the same thing.
2
0
209
Feb ’26
How to do settings icon for menu in SwiftUI?
Hi everyone. Can you help me with my settings icon design. I`m trying to create circular setting button using Menu. My code here: struct MenuView: View { var body: some View { Menu { Text("Hello") Text("How are you") } label: { Image(systemName: "gearshape.fill") .clipShape(Circle()) } .clipShape(Circle()) .padding(.top, 10) .padding(.leading, 20) } } You can see my try, this one looks wrong. It should be like this: Just Circle with setting image inside. Thank you an advance 😭🙏🛐
1
0
586
Feb ’26
SwiftUI Menu label: How to center an icon inside a circle?
Hi Everyone. Can you help me with my settings icon design. I'm trying to create a circular settings button using Menu. My code here: struct MenuView: View { var body: some View { Menu { Text("Hello") Text("How are you") } label: { Image(systemName: "gearshape.fill") .clipShape(Circle()) } .clipShape(Circle()) .padding(.top, 10) .padding(.leading, 20) } } You can see my try, this one looks wrong. It should be like this: Just Circle with setting image inside. Thank you an advance 😭🙏🛐
1
0
623
Feb ’26
Does Showing User's Current Location on the Map Require 'NSLocationWhenInUseUsageDescription'?
I have a desktop application that shows some real estate properties chosen by the user. The application shows those GPP locations on the map. The SwiftUI code is something like the following. import SwiftUI import MapKit struct ContentView: View { var body: some View ZStack { mapView } } private var mapView: some View { Map(position: $propertyViewModel.mapPosition) { ForEach(propertyViewModel.properties) { property in Annotation("", coordinate: CLLocationCoordinate2D(latitude: property.lat, longitude: property.lon)) { Button { } label: { VStack { Image(systemName: "house.circle.fill") .resizable() .scaledToFit() .frame(width: 48) .foregroundStyle(colorScheme == .light ? .white : .black) ... } } .buttonStyle(.borderless) } } UserAnnotation() } .mapControls { MapUserLocationButton() } .mapControlVisibility(.visible) .onAppear { CLLocationManager().requestWhenInUseAuthorization() } } } The application only wants to use the CLLocationManager class so that it can show those locations on the map relative to your current GPS position. And I'm hit with two review rejections. Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage Issue Description One or more purpose strings in the app do not sufficiently explain the use of protected resources. Purpose strings must clearly and completely describe the app's use of data and, in most cases, provide an example of how the data will be used. Guideline 5.1.5 - Legal - Privacy - Location Services The app uses location data for features that are not relevant to a user's location. Specifically, the app is not functional when Location Services are disabled. So I wonder if the application is even required to have 'NSLocationWhenInUseUsageDescription' and/or 'NSLocationUsageDescription'? just in order to show user's current location so that they can see property locations relative to it? The exact location privacy statement is the following. The application needs your permission in accessing your current location so that it will appear on the map
1
0
193
Feb ’26
Delete Confirmation Dialog Inside Toolbar IOS26
inline-code How do you achieve this effect in toolbar? Where is the documentation for this? How to make it appear top toolbar or bottom toolbar? Thank you! Here is what I have now... .toolbar { ToolbarItem(placement: .destructiveAction) { Button { showConfirm = true } label: { Image(systemName: "trash") .foregroundColor(.red) } } } .confirmationDialog( "Are you sure?", isPresented: $showConfirm, titleVisibility: .visible ) { Button("Delete Item", role: .destructive) { print("Deleted") } Button("Archive", role: .none) { print("Archived") } Button("Cancel", role: .cancel) { } } }
1
0
214
Feb ’26
How do i use dynamic data for my SwiftUI ScrollView without destroying performance?
Currently i am trying really hard to create experience like the Apple fitness app. So the main view is a single day and the user can swipe between days. The week would be displayed in the toolbar and provide a shortcut to scroll to the right day. I had many attempts at solving this and it can work. You can create such an interface with SwiftUI. However, changing the data on every scroll makes limiting view updates hard and additionally the updates are not related to my code directly. Instruments show me long updates, but they belong to SwiftUI and all the advice i found does not apply or help. struct ContentView: View { @State var journey = JourneyPrototype(selection: 0) @State var position: Int? = 0 var body: some View { ScrollView(.horizontal) { LazyHStack(spacing: 0) { ForEach(journey.collection, id: \.self) { index in Listing(index: index) .id(index) } } .scrollTargetLayout() } .scrollTargetBehavior(.paging) .scrollPosition(id: $position) .onChange(of: position) { oldValue, newValue in journey.selection = newValue ?? 0 journey.update() } .onScrollPhaseChange { oldPhase, newPhase in if newPhase == .idle { journey.commit() } } } } struct Listing: View { var index: Int var body: some View { List { Section { Text("Title") .font(.largeTitle) .padding() } Section { Text("\(index)") .font(.largeTitle) .padding() } Section { Text("1 ") Text("2 ") Text("3 ") Text("4 ") Text("5 ") Text("6 ") } } .containerRelativeFrame(.horizontal) } } @Observable class JourneyPrototype { var selection: Int var collection: [Int] var nextUp: [Int]? init(selection: Int) { self.selection = selection self.collection = [selection] Task { self.collection = [-2,-1,0,1,2] } } func update() { self.nextUp = [ self.selection - 2, self.selection - 1, selection, self.selection + 1, self.selection + 2 ] } func commit() { self.collection = self.nextUp ?? self.collection self.nextUp = nil } } #Preview { ContentView() } There are some major Problem with this abstracted prototype ScrollView has no good trigger for the update, because if i update on change of the position, it will update much more than once. Thats why i had to split calculation and applying the diff The LazyHStack is not optimal, because there are only 5 View in the example, but using HStack breaks the scrollPosition Each scroll updates all List, despite changing only 2 numbers in the array. AI recommended to append and remove, which does nothing about the updates. In my actual Code i do this with Identifiable data and the Problem is the same. So the data itself is not the problem? Please consider, this is just the rough prototype to explain the problem, i am aware that an array of Ints is not ideal here, but the problem is the same in Instruments and much shorter to post. Why am i posting this? Scrolling through dynamic data is required for many apps, but there is no proper solution to this online. Github and Blogs are fine with showing a progress indicator and letting the user wait, some probably perform worse than this prototype. Other solutions require UIKit like using a UIPageViewController. But even using this i run in small hitches related to layout. Important consideration, my data for the scrollview is too big to be calculated upfront. 100 years of days that are calculated for my domain logic take too long, so i have no network request, but the need to only act on a smaller window of data. Instruments shows long update for one scroll action tested on a iPhone SE 2nd generation ListRepresentable has 7 updates and takes 17ms LazySubViewPlacements has 2 updates and takes 8ms Other long updates are too verbose to include I would be very grateful for any help.
0
0
70
Feb ’26
SwiftUI onChange fires twice when filtering data from @Observable store
Hi all, I’m running into a “double update” effect in SwiftUI when using the @Observable with @State. I’m trying to understand whether this is expected behavior, a misuse on my side, or a potential bug. Setup I have an observable store using the Observation macro: @Observable class AlbumStore { var albums: [Album] = [ Album(id: "1", title: "Album 1", author: "user1"), Album(id: "2", title: "Album 2", author: "user1"), Album(id: "3", title: "Album 3", author: "user1"), Album(id: "4", title: "Album 4", author: "user1"), Album(id: "5", title: "Album 5", author: "user1"), Album(id: "6", title: "Album 6", author: "user1") ] func addAlbum(_ album: Album) { albums.insert(album, at: 0) } func removeAlbum(_ album: Album) { albums.removeAll(where: { $0 == album }) } } In my view, I inject it via @Environment and also keep some local state: @Environment(AlbumStore.self) var albumStore @State private var albumToAdd: Album? I derive a computed array that depends on both the environment store and local state: private var filteredAlbums: [Album] { let albums = albumStore.albums.filter { album in if let albumToAdd { return album.id != albumToAdd.id } else { return true } } return albums } View usage Inside a horizontal ScrollView / LazyHStack, I observe changes to filteredAlbums: @ViewBuilder private func carousel() -> some View { GeometryReader { proxy in let itemWidth: CGFloat = proxy.size.width / 3 let sideMargin = (proxy.size.width - itemWidth) / 2 ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 20) { ForEach(filteredAlbums, id: \.id) { album in albumItem(album: album) .frame(width: itemWidth) .scrollTransition(.interactive, axis: .horizontal) { content, phase in content .scaleEffect(phase.isIdentity ? 1.0 : 0.8) } } } .scrollTargetLayout() } .scrollTargetBehavior(.viewAligned(limitBehavior: .always)) .scrollPosition(id: $carouselScrollID, anchor: .center) .contentMargins(.horizontal, sideMargin, for: .scrollContent) .onChange(of: filteredAlbums) { old, new in print("filteredAlbums id: \(new.map { $0.id })") } } } Triggering the update When I add a new album, I do: albumToAdd = newAlbum albumStore.addAlbum(newAlbum) Expected behavior Since filteredAlbums explicitly filters out albumToAdd, I expect the result to remain unchanged. Actual behavior I consistently get two onChange callbacks, in this order: filteredAlbums id: ["E852E42A-AAEC-4360-A6A6-A95752805E2E", "1", "2", "3", "4", "5", "6"] filteredAlbums id: ["1", "2", "3", "4", "5", "6"] This suggests: The AlbumStore update (albums.insert) is observed first. The @State update (albumToAdd) is applied later. As a result, filteredAlbums is recomputed twice with different dependency snapshots. On a real iPad device, this also causes a visible scroll position jump. In the simulator, the jump is not visually observable; however, the onChange(of: filteredAlbums) callback still fires twice with the same sequence of values, indicating that the underlying state update behavior is identical. Strange observations This does not happen with ObservableObject If I replace @Observable with a classic ObservableObject + @Published: class OBAlbumStore: ObservableObject { @Published var albums: [Album] = [ Album(id: "1", title: "Album 1", author: "user1"), Album(id: "2", title: "Album 2", author: "user1"), Album(id: "3", title: "Album 3", author: "user1"), Album(id: "4", title: "Album 4", author: "user1"), Album(id: "5", title: "Album 5", author: "user1"), Album(id: "6", title: "Album 6", author: "user1") ] func addAlbum(_ album: Album) { albums.insert(album, at: 0) } func removeAlbum(_ album: Album) { albums.removeAll(where: { $0 == album }) } } …and inject it with @EnvironmentObject, the double update disappears. Removing GeometryReader also avoids the issue If I remove the surrounding GeometryReader and hardcode sizes: @ViewBuilder private func carousel() -> some View { // GeometryReader { proxy in let itemWidth: CGFloat = 400 let sideMargin: CGFloat = 410 ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 20) { ForEach(filteredAlbums, id: \.id) { album in albumItem(album: album) .frame(width: itemWidth) .scrollTransition(.interactive, axis: .horizontal) { content, phase in content .scaleEffect(phase.isIdentity ? 1.0 : 0.8) } } } .scrollTargetLayout() } .scrollTargetBehavior(.viewAligned(limitBehavior: .always)) .scrollPosition(id: $carouselScrollID, anchor: .center) .contentMargins(.horizontal, sideMargin, for: .scrollContent) .onChange(of: filteredAlbums) { old, new in print("filteredAlbums id: \(new.map { $0.id })") } // } } …the double onChange no longer occurs. Questions Is this update ordering expected when using @Observable and @State? Does Observation intentionally propagate environment changes before local state updates? Is GeometryReader forcing an additional evaluation pass that exposes this ordering? Is this a known limitation / bug compared to ObservableObject? I want to understand why this behaves differently under Observation. Thanks in advance for any insights 🙏 Full Project Link
2
1
207
Feb ’26
Showing 3D/AR content on multiple pages in iOS with RealityView
Hi. I'm trying to show 3D or AR content in multiple pages on an iOS app but I have found that if a RealityView is used earlier in a flow then future uses will never display the camera feed, even if those earlier uses do not use any spatial tracking. For example, in the following simplified view, the second page realityView will not display the camera feed even though the first view does not use it not start a tracking session. struct ContentView: View { var body: some View { NavigationStack { VStack { RealityView { content in content.camera = .virtual // showing model skipped for brevity } NavigationLink("Second Page") { RealityView { content in content.camera = .spatialTracking } } } } } } What is the way around this so that 3D content can be displayed in multiple places in the app without preventing AR content from working? I have also found the same problem when wrapping an ARView for use in SwiftUI.
0
0
309
Feb ’26
SwiftUI View Stops Updating When Using @Environment - Xcode 26
Hi all - i'm encountering a strange issue since updating to Xcode 26.0.1. It seems that any SwiftUI Views that have an :ObservedObject property that contains @Published properties, and use those properties inside the View, no longer update when those properties are updated when the view also has an @Environment property. If I remove the @Environment property and any usage of it, the view updates correctly. The specific environment property i'm using is .safeAreaInsets, like so: @Environment(\.safeAreaInsets) private var safeAreaInsets Is this a recognised bug in the latest iOS 26 SDK? Thanks
3
2
252
Feb ’26
File Download Support in SwiftUI Native WebView (iOS 26+)
I am using the native SwiftUI WebView and WebPage APIs (iOS 26+) and would like to implement file download functionality using the native SwiftUI WebView. However, I have not been able to find any APIs equivalent to WKDownload. In WKWebView, the WKDownload API can be used to handle downloads. I am looking for a similar API or recommended approach in the native SwiftUI WebView that would allow downloading files. If anyone has guidance or suggestions on how to implement this, I would appreciate your help.
0
1
455
Feb ’26
Cannot preview in this file – SwiftUI Preview referencing deleted simulator
I'm running Xcode 26.2 (17C52). After deleting all simulators and creating new ones, SwiftUI Preview stopped working. Xcode reports: “Simulator [D774B214-XXXX-XXXX-XXXX-XXXXXXXX8288] failed to boot and may have crashed.” However, when I list all available simulators using xcrun simctl list, there is no simulator with that identifier. It seems Xcode is still referencing a previously deleted simulator. I have tried: Deleting all simulators again Creating new simulators Restarting Xcode and the system But the issue persists and Preview still fails to launch. Has anyone encountered this issue or knows how to clear the cached simulator reference used by SwiftUI Preview?
2
0
103
Feb ’26
Text with .secondary vanishes when Material background is clipped to UnevenRoundedRectangle in ScrollView
I just found a weird bug: If you place a Text view using .foregroundStyle(.secondary), .tertiary, or other semantic colors inside a ScrollView, and apply a Material background clipped to an UnevenRoundedRectangle, the text becomes invisible. This issue does not occur when: The text uses .primary or explicit colors (e.g., .red, Color.blue), or The background is clipped to a standard shape (e.g., RoundedRectangle). A minimal reproducible example is shown below: ScrollView{ VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello World.") .font(.system(size: 15)) .foregroundStyle(.quinary) } } .padding() .frame(height: 100) .background(Material.regular) .clipShape(UnevenRoundedRectangle(topLeadingRadius: 10,bottomLeadingRadius: 8,bottomTrailingRadius:8, topTrailingRadius: 8))
1
0
291
Feb ’26
Layout issue using .strokeBorder modifier
Hello, Developers! While writing custom view modifier I ran into unexpected behavior of .strokeBorder modifier. The underlying content seem to be “bleeding” outside of the stroke border edges, even though they share the exact same shape for their layout. This issue relevant for both Xcode Previews and on-device testing. Maybe someone has experienced this issue before, I'd be glad to see your opinion on this matter.
1
0
156
Feb ’26
Animation does not work with List, while works with ScrollView + ForEach
Why there is a working animation with ScrollView + ForEach of items removal, but there is none with List? ScrollView + ForEach: struct ContentView: View { @State var items: [String] = Array(1...5).map(\.description) var body: some View { ScrollView(.vertical) { ForEach(items, id: \.self) { item in Text(String(item)) .frame(maxWidth: .infinity, minHeight: 50) .background(.gray) .onTapGesture { withAnimation(.linear(duration: 0.1)) { items = items.filter { $0 != item } } } } } } } List: struct ContentView: View { @State var items: [String] = Array(1...5).map(\.description) var body: some View { List(items, id: \.self) { item in Text(String(item)) .frame(maxWidth: .infinity, minHeight: 50) .background(.gray) .onTapGesture { withAnimation(.linear(duration: 0.1)) { items = items.filter { $0 != item } } } } } }```
6
1
267
Feb ’26
screenshot on iOS26
I had take screenshots by following code let scenes = UIApplication.shared.connectedScenes let windowScene = scenes.first as? UIWindowScene let window = windowScene?.windows.first self.uiImage = window?.rootViewController?.view!.getImage(rect: rect) View has two views. One is ImageView contains some image and overlay of image detection results with .overlay. another view is InfoView contains several info and button which above code fired. on iOS 17, I can take screenshots as I saw, but on iOS26, missing on image of ImageView. Overlay(detected rectangle) in Imageview and InfView can be taken. How can I take screenshots as I saw on iOS26?(iPad)
10
0
748
Feb ’26
Does anyone know how to achieve this custom MKAnnotation?
I’ve notice that in Maps, some pins contain images and do not have the little triangle at the bottom of it, yet they still animate the same when clicked. How could this be achieved? I believe the name of this annotation is MKMapFeatureAnnotation. I've tried this and it did not give the same result. I'm able to create a custom MKMarkerAnnotationView but it does not animate the same (balloon animation like the MKMapFeatureAnnotation). I was looking forward to create a custom MKMapFeatureAnnotation similar in design which would animate the same. Unfortunately, I cannot create a custom MKMapFeatureAnnotation because everything is privated
0
0
231
Feb ’26
iOS 26 & Xcode 26 - bug with keyboard by WebView
Environment iOS 26 (23A343) Xcode 26 Reproduces on device and Simulator Description When presenting a SwiftUI WebView (native iOS 26 component) or a WKWebView/UIWebView via UIViewRepresentable, focusing a text field inside the web view and then dismissing it breaks the keyboard layout behavior. After returning to the main app, tapping any TextField causes the keyboard to cover bottom controls (e.g. buttons). Expected safe area insets are not applied. The issue is only resolved after closing and reopening the keyboard once. Steps to Reproduce Open a SwiftUI screen with WebView (via .sheet or NavigationLink). Inside the web view, tap a text field to show the keyboard. Dismiss the web view. Tap a TextField in the main app. Expected Result Layout should adjust correctly. Bottom controls stay visible above the keyboard. Actual Result Keyboard covers bottom controls. Insets are ignored until the keyboard is dismissed and reopened. Notes Reproduces with: Native SwiftUI WebView (iOS 26) WKWebView and UIWebView via UIViewRepresentable Presentation style (.sheet or navigation push) does not matter. Example video: https://youtu.be/Epgoz1vETKU FB: FB20386257 Sample Code import SwiftUI import WebKit struct ContentView: View { @State var url: URL? @FocusState private var isFocused: Bool var body: some View { VStack { TextField("TextField", text: .constant("")) .focused($isFocused) Button("HIDE KEYBOARD") { isFocused = false } Spacer() Button("ACTION") { url = URL(string: "https://google.com") } } .sheet(item: $url) { value in NavigationStack { WebView(url: value) .toolbar { ToolbarItem(placement: .topBarLeading) { Button("CLOSE") { url = nil } } } } } } } extension URL: Identifiable { public var id: String { absoluteString } }
2
5
1.2k
Feb ’26
Animation Glitch behind Tab-bar
I'm trying to replicate edit/select mode of iOS 26 photos app. When user clicks Select button, bottom tab bar is replaced by the toolbar buttons. When I press Done button, a white opaque bar appears at the bottom behind the tabbar. It looks pretty straightforward to implement but I'm banging my head here now. Any help will be appreciated. Code and animation frames attached bellow struct ContentView: View { var body: some View { TabView(selection: $selectedTab) { OverviewView() .tabItem { Image(systemName: "chart.pie") Text("Overview") } .tag(0) //rest of the tabs } } } struct OverviewView: View { @State private var editActive = false @State private var selection = Set<String>() @State private var items = [ "Item 1", "Item 2", "Item 3", ] var body: some View { NavigationStack { List(selection: $selection) { ForEach(items, id: \.self) { item in Text(item) } } .toolbar { if editActive { ToolbarItem(placement: .bottomBar) { Button { } label: { Label("Delete", systemImage: "trash") } } ToolbarItem(placement: .bottomBar) { Button { } label: { Label("Category", systemImage: "tag") } } } ToolbarItem(placement: .topBarTrailing) { Button(editActive ? "Done" : "Select") { withAnimation { editActive.toggle() } } } } .environment(\.editMode, .constant(editActive ? .active : .inactive)) .toolbar(editActive ? .hidden : .visible, for: .tabBar) } } } I have attached 5 frames during animation phase.
1
0
127
Feb ’26
.glassEffect() renders dark on device but works on simulator - TestFlight doesn't fix it
iOS 26 SwiftUI .glassEffect() renders dark/gray on physical device - TestFlight doesn't fix it .glassEffect() renders as dark/muddy gray on my physical iPhone instead of the light frosted glass like Apple Music's tab bar. What I've confirmed: Same code works perfectly on iOS Simulator Apple Music and other Apple apps show correct Liquid Glass on same device Brand new Xcode project with just .glassEffect() also renders dark TestFlight build (App Store signing) has the SAME problem - still dark/gray This rules out developer signing vs App Store signing as the cause What I've tried: Clean build, delete derived data, reinstall app Completely reinstalled Xcode All accessibility settings correct (Reduce Transparency OFF, Liquid Glass set to Clear) Disabled Metal diagnostics Debug and Release builds Added window configuration for Extended sRGB/P3 color space Added AppDelegate with configureWindowForLiquidGlass() Tried .preferredColorScheme(nil) Tried background animation to force "live" rendering Environment: iPhone 17 Pro, iOS 26.3 Xcode 26.2 macOS 26.3 The question: Why does .glassEffect() work for Apple's apps but not third party apps, even with App Store signing via TestFlight? What am I missing?
5
0
312
Feb ’26
Titles and Header Auto Changing Color?
I have some questions about Liquid Glass and iOS 26 on the iPhone. Routine scrolling transactions in any view are causing the title to change from Light Mode colors to Dark Mode colors. Is this now standard operation? The column headers are also displaying a black stripe across the top of the screen when scrolling. So why doesn't the display shift when in Dark Mode to Light mode? Scrolling is causing everything in the header (navigation title, time, battery status, and wi-fi status) to change from black to white. Is this an accessibility action that I may have turned on by accident? I'm not very thrilled by this behavior!
Topic: Design SubTopic: General Tags:
7
0
1.2k
Feb ’26
SwiftUI List: observable reference types not deallocated immediately after refresh
Hello 👋 I ran into a SwiftUI lifecycle gotcha while debugging a List with .refreshable I share the code used to reproduce the issue @Observable final class CounterModel: Identifiable { let id: String var title: String var value: Int init(id: String, title: String, value: Int = 0) { self.id = id self.title = title self.value = value } deinit { print("deinit", title) } } @Observable final class ObservableCountersStore { var counters: [CounterModel] = [ .init(id: "1", title: "A"), .init(id: "2", title: "B"), .init(id: "3", title: "C") ] func refresh() async { try? await Task.sleep(nanoseconds: 300_000_000) counters = [.init(id: "4", title: "D")] } } struct ObservableCountersListView: View { @State private var store = ObservableCountersStore() var body: some View { List { ForEach(store.counters) { counter in ObservableCounterRow(counter: counter) } } .refreshable { await store.refresh() } } } struct ObservableCounterRow: View { let counter: CounterModel var body: some View { Text(counter.title) } } Observation: After calling refresh(), only some of the previous CounterModel only one CounterModel is deallocated immediately. Others are retained This doesn’t look like a leak, but it made me realize that passing observable reference types directly into List rows leads to non-deterministic object lifetimes, especially with .refreshable. Posting this as a gotcha — curious if this matches intended behavior or if others have run into the same thing.
Replies
2
Boosts
0
Views
209
Activity
Feb ’26
How to do settings icon for menu in SwiftUI?
Hi everyone. Can you help me with my settings icon design. I`m trying to create circular setting button using Menu. My code here: struct MenuView: View { var body: some View { Menu { Text("Hello") Text("How are you") } label: { Image(systemName: "gearshape.fill") .clipShape(Circle()) } .clipShape(Circle()) .padding(.top, 10) .padding(.leading, 20) } } You can see my try, this one looks wrong. It should be like this: Just Circle with setting image inside. Thank you an advance 😭🙏🛐
Replies
1
Boosts
0
Views
586
Activity
Feb ’26
SwiftUI Menu label: How to center an icon inside a circle?
Hi Everyone. Can you help me with my settings icon design. I'm trying to create a circular settings button using Menu. My code here: struct MenuView: View { var body: some View { Menu { Text("Hello") Text("How are you") } label: { Image(systemName: "gearshape.fill") .clipShape(Circle()) } .clipShape(Circle()) .padding(.top, 10) .padding(.leading, 20) } } You can see my try, this one looks wrong. It should be like this: Just Circle with setting image inside. Thank you an advance 😭🙏🛐
Replies
1
Boosts
0
Views
623
Activity
Feb ’26
Does Showing User's Current Location on the Map Require 'NSLocationWhenInUseUsageDescription'?
I have a desktop application that shows some real estate properties chosen by the user. The application shows those GPP locations on the map. The SwiftUI code is something like the following. import SwiftUI import MapKit struct ContentView: View { var body: some View ZStack { mapView } } private var mapView: some View { Map(position: $propertyViewModel.mapPosition) { ForEach(propertyViewModel.properties) { property in Annotation("", coordinate: CLLocationCoordinate2D(latitude: property.lat, longitude: property.lon)) { Button { } label: { VStack { Image(systemName: "house.circle.fill") .resizable() .scaledToFit() .frame(width: 48) .foregroundStyle(colorScheme == .light ? .white : .black) ... } } .buttonStyle(.borderless) } } UserAnnotation() } .mapControls { MapUserLocationButton() } .mapControlVisibility(.visible) .onAppear { CLLocationManager().requestWhenInUseAuthorization() } } } The application only wants to use the CLLocationManager class so that it can show those locations on the map relative to your current GPS position. And I'm hit with two review rejections. Guideline 5.1.1 - Legal - Privacy - Data Collection and Storage Issue Description One or more purpose strings in the app do not sufficiently explain the use of protected resources. Purpose strings must clearly and completely describe the app's use of data and, in most cases, provide an example of how the data will be used. Guideline 5.1.5 - Legal - Privacy - Location Services The app uses location data for features that are not relevant to a user's location. Specifically, the app is not functional when Location Services are disabled. So I wonder if the application is even required to have 'NSLocationWhenInUseUsageDescription' and/or 'NSLocationUsageDescription'? just in order to show user's current location so that they can see property locations relative to it? The exact location privacy statement is the following. The application needs your permission in accessing your current location so that it will appear on the map
Replies
1
Boosts
0
Views
193
Activity
Feb ’26
Delete Confirmation Dialog Inside Toolbar IOS26
inline-code How do you achieve this effect in toolbar? Where is the documentation for this? How to make it appear top toolbar or bottom toolbar? Thank you! Here is what I have now... .toolbar { ToolbarItem(placement: .destructiveAction) { Button { showConfirm = true } label: { Image(systemName: "trash") .foregroundColor(.red) } } } .confirmationDialog( "Are you sure?", isPresented: $showConfirm, titleVisibility: .visible ) { Button("Delete Item", role: .destructive) { print("Deleted") } Button("Archive", role: .none) { print("Archived") } Button("Cancel", role: .cancel) { } } }
Replies
1
Boosts
0
Views
214
Activity
Feb ’26
How do i use dynamic data for my SwiftUI ScrollView without destroying performance?
Currently i am trying really hard to create experience like the Apple fitness app. So the main view is a single day and the user can swipe between days. The week would be displayed in the toolbar and provide a shortcut to scroll to the right day. I had many attempts at solving this and it can work. You can create such an interface with SwiftUI. However, changing the data on every scroll makes limiting view updates hard and additionally the updates are not related to my code directly. Instruments show me long updates, but they belong to SwiftUI and all the advice i found does not apply or help. struct ContentView: View { @State var journey = JourneyPrototype(selection: 0) @State var position: Int? = 0 var body: some View { ScrollView(.horizontal) { LazyHStack(spacing: 0) { ForEach(journey.collection, id: \.self) { index in Listing(index: index) .id(index) } } .scrollTargetLayout() } .scrollTargetBehavior(.paging) .scrollPosition(id: $position) .onChange(of: position) { oldValue, newValue in journey.selection = newValue ?? 0 journey.update() } .onScrollPhaseChange { oldPhase, newPhase in if newPhase == .idle { journey.commit() } } } } struct Listing: View { var index: Int var body: some View { List { Section { Text("Title") .font(.largeTitle) .padding() } Section { Text("\(index)") .font(.largeTitle) .padding() } Section { Text("1 ") Text("2 ") Text("3 ") Text("4 ") Text("5 ") Text("6 ") } } .containerRelativeFrame(.horizontal) } } @Observable class JourneyPrototype { var selection: Int var collection: [Int] var nextUp: [Int]? init(selection: Int) { self.selection = selection self.collection = [selection] Task { self.collection = [-2,-1,0,1,2] } } func update() { self.nextUp = [ self.selection - 2, self.selection - 1, selection, self.selection + 1, self.selection + 2 ] } func commit() { self.collection = self.nextUp ?? self.collection self.nextUp = nil } } #Preview { ContentView() } There are some major Problem with this abstracted prototype ScrollView has no good trigger for the update, because if i update on change of the position, it will update much more than once. Thats why i had to split calculation and applying the diff The LazyHStack is not optimal, because there are only 5 View in the example, but using HStack breaks the scrollPosition Each scroll updates all List, despite changing only 2 numbers in the array. AI recommended to append and remove, which does nothing about the updates. In my actual Code i do this with Identifiable data and the Problem is the same. So the data itself is not the problem? Please consider, this is just the rough prototype to explain the problem, i am aware that an array of Ints is not ideal here, but the problem is the same in Instruments and much shorter to post. Why am i posting this? Scrolling through dynamic data is required for many apps, but there is no proper solution to this online. Github and Blogs are fine with showing a progress indicator and letting the user wait, some probably perform worse than this prototype. Other solutions require UIKit like using a UIPageViewController. But even using this i run in small hitches related to layout. Important consideration, my data for the scrollview is too big to be calculated upfront. 100 years of days that are calculated for my domain logic take too long, so i have no network request, but the need to only act on a smaller window of data. Instruments shows long update for one scroll action tested on a iPhone SE 2nd generation ListRepresentable has 7 updates and takes 17ms LazySubViewPlacements has 2 updates and takes 8ms Other long updates are too verbose to include I would be very grateful for any help.
Replies
0
Boosts
0
Views
70
Activity
Feb ’26
SwiftUI onChange fires twice when filtering data from @Observable store
Hi all, I’m running into a “double update” effect in SwiftUI when using the @Observable with @State. I’m trying to understand whether this is expected behavior, a misuse on my side, or a potential bug. Setup I have an observable store using the Observation macro: @Observable class AlbumStore { var albums: [Album] = [ Album(id: "1", title: "Album 1", author: "user1"), Album(id: "2", title: "Album 2", author: "user1"), Album(id: "3", title: "Album 3", author: "user1"), Album(id: "4", title: "Album 4", author: "user1"), Album(id: "5", title: "Album 5", author: "user1"), Album(id: "6", title: "Album 6", author: "user1") ] func addAlbum(_ album: Album) { albums.insert(album, at: 0) } func removeAlbum(_ album: Album) { albums.removeAll(where: { $0 == album }) } } In my view, I inject it via @Environment and also keep some local state: @Environment(AlbumStore.self) var albumStore @State private var albumToAdd: Album? I derive a computed array that depends on both the environment store and local state: private var filteredAlbums: [Album] { let albums = albumStore.albums.filter { album in if let albumToAdd { return album.id != albumToAdd.id } else { return true } } return albums } View usage Inside a horizontal ScrollView / LazyHStack, I observe changes to filteredAlbums: @ViewBuilder private func carousel() -> some View { GeometryReader { proxy in let itemWidth: CGFloat = proxy.size.width / 3 let sideMargin = (proxy.size.width - itemWidth) / 2 ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 20) { ForEach(filteredAlbums, id: \.id) { album in albumItem(album: album) .frame(width: itemWidth) .scrollTransition(.interactive, axis: .horizontal) { content, phase in content .scaleEffect(phase.isIdentity ? 1.0 : 0.8) } } } .scrollTargetLayout() } .scrollTargetBehavior(.viewAligned(limitBehavior: .always)) .scrollPosition(id: $carouselScrollID, anchor: .center) .contentMargins(.horizontal, sideMargin, for: .scrollContent) .onChange(of: filteredAlbums) { old, new in print("filteredAlbums id: \(new.map { $0.id })") } } } Triggering the update When I add a new album, I do: albumToAdd = newAlbum albumStore.addAlbum(newAlbum) Expected behavior Since filteredAlbums explicitly filters out albumToAdd, I expect the result to remain unchanged. Actual behavior I consistently get two onChange callbacks, in this order: filteredAlbums id: ["E852E42A-AAEC-4360-A6A6-A95752805E2E", "1", "2", "3", "4", "5", "6"] filteredAlbums id: ["1", "2", "3", "4", "5", "6"] This suggests: The AlbumStore update (albums.insert) is observed first. The @State update (albumToAdd) is applied later. As a result, filteredAlbums is recomputed twice with different dependency snapshots. On a real iPad device, this also causes a visible scroll position jump. In the simulator, the jump is not visually observable; however, the onChange(of: filteredAlbums) callback still fires twice with the same sequence of values, indicating that the underlying state update behavior is identical. Strange observations This does not happen with ObservableObject If I replace @Observable with a classic ObservableObject + @Published: class OBAlbumStore: ObservableObject { @Published var albums: [Album] = [ Album(id: "1", title: "Album 1", author: "user1"), Album(id: "2", title: "Album 2", author: "user1"), Album(id: "3", title: "Album 3", author: "user1"), Album(id: "4", title: "Album 4", author: "user1"), Album(id: "5", title: "Album 5", author: "user1"), Album(id: "6", title: "Album 6", author: "user1") ] func addAlbum(_ album: Album) { albums.insert(album, at: 0) } func removeAlbum(_ album: Album) { albums.removeAll(where: { $0 == album }) } } …and inject it with @EnvironmentObject, the double update disappears. Removing GeometryReader also avoids the issue If I remove the surrounding GeometryReader and hardcode sizes: @ViewBuilder private func carousel() -> some View { // GeometryReader { proxy in let itemWidth: CGFloat = 400 let sideMargin: CGFloat = 410 ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 20) { ForEach(filteredAlbums, id: \.id) { album in albumItem(album: album) .frame(width: itemWidth) .scrollTransition(.interactive, axis: .horizontal) { content, phase in content .scaleEffect(phase.isIdentity ? 1.0 : 0.8) } } } .scrollTargetLayout() } .scrollTargetBehavior(.viewAligned(limitBehavior: .always)) .scrollPosition(id: $carouselScrollID, anchor: .center) .contentMargins(.horizontal, sideMargin, for: .scrollContent) .onChange(of: filteredAlbums) { old, new in print("filteredAlbums id: \(new.map { $0.id })") } // } } …the double onChange no longer occurs. Questions Is this update ordering expected when using @Observable and @State? Does Observation intentionally propagate environment changes before local state updates? Is GeometryReader forcing an additional evaluation pass that exposes this ordering? Is this a known limitation / bug compared to ObservableObject? I want to understand why this behaves differently under Observation. Thanks in advance for any insights 🙏 Full Project Link
Replies
2
Boosts
1
Views
207
Activity
Feb ’26
Showing 3D/AR content on multiple pages in iOS with RealityView
Hi. I'm trying to show 3D or AR content in multiple pages on an iOS app but I have found that if a RealityView is used earlier in a flow then future uses will never display the camera feed, even if those earlier uses do not use any spatial tracking. For example, in the following simplified view, the second page realityView will not display the camera feed even though the first view does not use it not start a tracking session. struct ContentView: View { var body: some View { NavigationStack { VStack { RealityView { content in content.camera = .virtual // showing model skipped for brevity } NavigationLink("Second Page") { RealityView { content in content.camera = .spatialTracking } } } } } } What is the way around this so that 3D content can be displayed in multiple places in the app without preventing AR content from working? I have also found the same problem when wrapping an ARView for use in SwiftUI.
Replies
0
Boosts
0
Views
309
Activity
Feb ’26
SwiftUI View Stops Updating When Using @Environment - Xcode 26
Hi all - i'm encountering a strange issue since updating to Xcode 26.0.1. It seems that any SwiftUI Views that have an :ObservedObject property that contains @Published properties, and use those properties inside the View, no longer update when those properties are updated when the view also has an @Environment property. If I remove the @Environment property and any usage of it, the view updates correctly. The specific environment property i'm using is .safeAreaInsets, like so: @Environment(\.safeAreaInsets) private var safeAreaInsets Is this a recognised bug in the latest iOS 26 SDK? Thanks
Replies
3
Boosts
2
Views
252
Activity
Feb ’26
File Download Support in SwiftUI Native WebView (iOS 26+)
I am using the native SwiftUI WebView and WebPage APIs (iOS 26+) and would like to implement file download functionality using the native SwiftUI WebView. However, I have not been able to find any APIs equivalent to WKDownload. In WKWebView, the WKDownload API can be used to handle downloads. I am looking for a similar API or recommended approach in the native SwiftUI WebView that would allow downloading files. If anyone has guidance or suggestions on how to implement this, I would appreciate your help.
Replies
0
Boosts
1
Views
455
Activity
Feb ’26
Cannot preview in this file – SwiftUI Preview referencing deleted simulator
I'm running Xcode 26.2 (17C52). After deleting all simulators and creating new ones, SwiftUI Preview stopped working. Xcode reports: “Simulator [D774B214-XXXX-XXXX-XXXX-XXXXXXXX8288] failed to boot and may have crashed.” However, when I list all available simulators using xcrun simctl list, there is no simulator with that identifier. It seems Xcode is still referencing a previously deleted simulator. I have tried: Deleting all simulators again Creating new simulators Restarting Xcode and the system But the issue persists and Preview still fails to launch. Has anyone encountered this issue or knows how to clear the cached simulator reference used by SwiftUI Preview?
Replies
2
Boosts
0
Views
103
Activity
Feb ’26
Text with .secondary vanishes when Material background is clipped to UnevenRoundedRectangle in ScrollView
I just found a weird bug: If you place a Text view using .foregroundStyle(.secondary), .tertiary, or other semantic colors inside a ScrollView, and apply a Material background clipped to an UnevenRoundedRectangle, the text becomes invisible. This issue does not occur when: The text uses .primary or explicit colors (e.g., .red, Color.blue), or The background is clipped to a standard shape (e.g., RoundedRectangle). A minimal reproducible example is shown below: ScrollView{ VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello World.") .font(.system(size: 15)) .foregroundStyle(.quinary) } } .padding() .frame(height: 100) .background(Material.regular) .clipShape(UnevenRoundedRectangle(topLeadingRadius: 10,bottomLeadingRadius: 8,bottomTrailingRadius:8, topTrailingRadius: 8))
Replies
1
Boosts
0
Views
291
Activity
Feb ’26
Layout issue using .strokeBorder modifier
Hello, Developers! While writing custom view modifier I ran into unexpected behavior of .strokeBorder modifier. The underlying content seem to be “bleeding” outside of the stroke border edges, even though they share the exact same shape for their layout. This issue relevant for both Xcode Previews and on-device testing. Maybe someone has experienced this issue before, I'd be glad to see your opinion on this matter.
Replies
1
Boosts
0
Views
156
Activity
Feb ’26
Animation does not work with List, while works with ScrollView + ForEach
Why there is a working animation with ScrollView + ForEach of items removal, but there is none with List? ScrollView + ForEach: struct ContentView: View { @State var items: [String] = Array(1...5).map(\.description) var body: some View { ScrollView(.vertical) { ForEach(items, id: \.self) { item in Text(String(item)) .frame(maxWidth: .infinity, minHeight: 50) .background(.gray) .onTapGesture { withAnimation(.linear(duration: 0.1)) { items = items.filter { $0 != item } } } } } } } List: struct ContentView: View { @State var items: [String] = Array(1...5).map(\.description) var body: some View { List(items, id: \.self) { item in Text(String(item)) .frame(maxWidth: .infinity, minHeight: 50) .background(.gray) .onTapGesture { withAnimation(.linear(duration: 0.1)) { items = items.filter { $0 != item } } } } } }```
Replies
6
Boosts
1
Views
267
Activity
Feb ’26
screenshot on iOS26
I had take screenshots by following code let scenes = UIApplication.shared.connectedScenes let windowScene = scenes.first as? UIWindowScene let window = windowScene?.windows.first self.uiImage = window?.rootViewController?.view!.getImage(rect: rect) View has two views. One is ImageView contains some image and overlay of image detection results with .overlay. another view is InfoView contains several info and button which above code fired. on iOS 17, I can take screenshots as I saw, but on iOS26, missing on image of ImageView. Overlay(detected rectangle) in Imageview and InfView can be taken. How can I take screenshots as I saw on iOS26?(iPad)
Replies
10
Boosts
0
Views
748
Activity
Feb ’26
Does anyone know how to achieve this custom MKAnnotation?
I’ve notice that in Maps, some pins contain images and do not have the little triangle at the bottom of it, yet they still animate the same when clicked. How could this be achieved? I believe the name of this annotation is MKMapFeatureAnnotation. I've tried this and it did not give the same result. I'm able to create a custom MKMarkerAnnotationView but it does not animate the same (balloon animation like the MKMapFeatureAnnotation). I was looking forward to create a custom MKMapFeatureAnnotation similar in design which would animate the same. Unfortunately, I cannot create a custom MKMapFeatureAnnotation because everything is privated
Replies
0
Boosts
0
Views
231
Activity
Feb ’26
iOS 26 & Xcode 26 - bug with keyboard by WebView
Environment iOS 26 (23A343) Xcode 26 Reproduces on device and Simulator Description When presenting a SwiftUI WebView (native iOS 26 component) or a WKWebView/UIWebView via UIViewRepresentable, focusing a text field inside the web view and then dismissing it breaks the keyboard layout behavior. After returning to the main app, tapping any TextField causes the keyboard to cover bottom controls (e.g. buttons). Expected safe area insets are not applied. The issue is only resolved after closing and reopening the keyboard once. Steps to Reproduce Open a SwiftUI screen with WebView (via .sheet or NavigationLink). Inside the web view, tap a text field to show the keyboard. Dismiss the web view. Tap a TextField in the main app. Expected Result Layout should adjust correctly. Bottom controls stay visible above the keyboard. Actual Result Keyboard covers bottom controls. Insets are ignored until the keyboard is dismissed and reopened. Notes Reproduces with: Native SwiftUI WebView (iOS 26) WKWebView and UIWebView via UIViewRepresentable Presentation style (.sheet or navigation push) does not matter. Example video: https://youtu.be/Epgoz1vETKU FB: FB20386257 Sample Code import SwiftUI import WebKit struct ContentView: View { @State var url: URL? @FocusState private var isFocused: Bool var body: some View { VStack { TextField("TextField", text: .constant("")) .focused($isFocused) Button("HIDE KEYBOARD") { isFocused = false } Spacer() Button("ACTION") { url = URL(string: "https://google.com") } } .sheet(item: $url) { value in NavigationStack { WebView(url: value) .toolbar { ToolbarItem(placement: .topBarLeading) { Button("CLOSE") { url = nil } } } } } } } extension URL: Identifiable { public var id: String { absoluteString } }
Replies
2
Boosts
5
Views
1.2k
Activity
Feb ’26
Animation Glitch behind Tab-bar
I'm trying to replicate edit/select mode of iOS 26 photos app. When user clicks Select button, bottom tab bar is replaced by the toolbar buttons. When I press Done button, a white opaque bar appears at the bottom behind the tabbar. It looks pretty straightforward to implement but I'm banging my head here now. Any help will be appreciated. Code and animation frames attached bellow struct ContentView: View { var body: some View { TabView(selection: $selectedTab) { OverviewView() .tabItem { Image(systemName: "chart.pie") Text("Overview") } .tag(0) //rest of the tabs } } } struct OverviewView: View { @State private var editActive = false @State private var selection = Set<String>() @State private var items = [ "Item 1", "Item 2", "Item 3", ] var body: some View { NavigationStack { List(selection: $selection) { ForEach(items, id: \.self) { item in Text(item) } } .toolbar { if editActive { ToolbarItem(placement: .bottomBar) { Button { } label: { Label("Delete", systemImage: "trash") } } ToolbarItem(placement: .bottomBar) { Button { } label: { Label("Category", systemImage: "tag") } } } ToolbarItem(placement: .topBarTrailing) { Button(editActive ? "Done" : "Select") { withAnimation { editActive.toggle() } } } } .environment(\.editMode, .constant(editActive ? .active : .inactive)) .toolbar(editActive ? .hidden : .visible, for: .tabBar) } } } I have attached 5 frames during animation phase.
Replies
1
Boosts
0
Views
127
Activity
Feb ’26
.glassEffect() renders dark on device but works on simulator - TestFlight doesn't fix it
iOS 26 SwiftUI .glassEffect() renders dark/gray on physical device - TestFlight doesn't fix it .glassEffect() renders as dark/muddy gray on my physical iPhone instead of the light frosted glass like Apple Music's tab bar. What I've confirmed: Same code works perfectly on iOS Simulator Apple Music and other Apple apps show correct Liquid Glass on same device Brand new Xcode project with just .glassEffect() also renders dark TestFlight build (App Store signing) has the SAME problem - still dark/gray This rules out developer signing vs App Store signing as the cause What I've tried: Clean build, delete derived data, reinstall app Completely reinstalled Xcode All accessibility settings correct (Reduce Transparency OFF, Liquid Glass set to Clear) Disabled Metal diagnostics Debug and Release builds Added window configuration for Extended sRGB/P3 color space Added AppDelegate with configureWindowForLiquidGlass() Tried .preferredColorScheme(nil) Tried background animation to force "live" rendering Environment: iPhone 17 Pro, iOS 26.3 Xcode 26.2 macOS 26.3 The question: Why does .glassEffect() work for Apple's apps but not third party apps, even with App Store signing via TestFlight? What am I missing?
Replies
5
Boosts
0
Views
312
Activity
Feb ’26
Titles and Header Auto Changing Color?
I have some questions about Liquid Glass and iOS 26 on the iPhone. Routine scrolling transactions in any view are causing the title to change from Light Mode colors to Dark Mode colors. Is this now standard operation? The column headers are also displaying a black stripe across the top of the screen when scrolling. So why doesn't the display shift when in Dark Mode to Light mode? Scrolling is causing everything in the header (navigation title, time, battery status, and wi-fi status) to change from black to white. Is this an accessibility action that I may have turned on by accident? I'm not very thrilled by this behavior!
Topic: Design SubTopic: General Tags:
Replies
7
Boosts
0
Views
1.2k
Activity
Feb ’26