Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

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

SwiftUI Documentation

Posts under SwiftUI subtopic

Post

Replies

Boosts

Views

Activity

MapKit elevation information for a route
Hello all, I am playing with MapKit for SwiftUI, so far so good. There is one thing I have not seen any documentations, or sample codes around and that's elevation data, e.g. My questions are: Is there a way to get this information from an MKRoute? Is it possible to get the elevation gain/drop at a given point in the route? Many thank in advance for your help.
1
1
633
Oct ’23
How to Change Picker Text Color In SwiftUI
I try to change picker text color but, it does not work. As you see, "City" and "District"'s color are blue but, I'd like to make them white. I have tried below codes but, they do not work. Do you know any methods for that ? Picker("İl", selection: $selectedCity) { ForEach(turkishCities, id: \.self) { city in Text(city) .foregroundColor(.white) } } Picker("İlçe", selection: $selectedDistrict) { ForEach(cityDistricts[selectedCity] ?? [], id: \.self) { district in Text(district) .foregroundColor(Color.white) } } .onAppear { UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .normal) } Thank you in advance.
3
0
9.3k
Oct ’23
Swift Charts performance when displaying many data points
I'm currently evaluating Swift Charts to use in my macOS app, where I need to (potentially) display a few millions of data points, ideally all of them at one time. I want to give users the possibility to zoom in & out, so the entire range of values could be displayed at one moment. However, starting at around 20K data points (on my computer), the Chart takes a little bit to set up, but the window resizing is laggy. The performance seems to decrease linearly (?), when dealing with 100K data points you can barely resize the window and the Chart setup/creation is noticeable enough. Dealing with 500K data points is out of the question, the app is pretty much not useable. So I'm wondering if anybody else had a similar issue and what can be done? Is there any "magic" Swift Charts setting that could improve the performance? I have a "data decimation" algorithm, and given no choice I will use it, but somehow I was hoping for Swift Charts to gracefully handle at least 100K data points (there are other libs which do this!). Also, limiting the displayed data range is out of the question for my case, this is a crucial feature of the app. Here's the code that I'm using, but it's the most basic one: struct DataPoint: Identifiable { var id: Double { Double(xValue) } let xValue: Int let yValue: Double } let dataPoints: [DataPoint] = (0..<100_000).map { DataPoint(xValue: $0, yValue: Double($0)) } struct MyChart: View { var body: some View { Chart(dataPoints) { dataPoint in PointMark(x: .value("Index", dataPoint.xValue), y: .value("Y Value", dataPoint.yValue)) } } } Some additional info, if it helps: The Chart is included in a AppKit window via NSHostingController (in my sample project the window contains nothing but the chart) The computer is a MacBook Pro, 2019 and is running macOS 10.14
4
2
1.8k
Oct ’23
Sheet will change to dark theme from toggle but won't change back to light mode
I have my ContentView which has a Sheet that will appear when a button is pressed. struct ContentView: View { @EnvironmentObject private var settings: SettingsHandler @State private var settingsView: Bool = false var body: some View { NavigationStack { Button(action: { settingsView.toggle() }, label: { Image(systemName: "gearshape.fill") }) } .preferredColorScheme(settings.darkTheme ? .dark : nil) .sheet(isPresented: $settingsView, content: { SettingsView() }) } } Let's say the app is in light mode based on the phones theme settings. You open the SettingsView and select the toggle that will switch to dark mode. Everything changes to dark mode, including the SettingsView sheet. Then you select the same toggle to switch back and ContentView in the background changes to light theme but the sheet doesn't until you close and reopen it. I would think it would change back considering it changed to dark mode without needing to be closed. I tried attaching an ID to the SettingsView and having it refresh when settings.darkTheme is changed, however, it doesn't seem to be doing anything. I also added the .preferredColorScheme() modifier into the SettingsView, but it did nothing. I also replaced the nil to .light, and the same issue occurred. Settings is an EnvironmentObject that I created to manage all the Settings I have. At the moment, I'm thinking I can have the sheet just close and reopen, however, I would like for it to update properly. Any ideas?
2
0
1.8k
Oct ’23
SwiftData does not cascade delete
Even if there are one-many relationship models with the cascade delete rule, SwiftData does not cascade delete items. For example, there is one school has multiple students like the following models, and even when the school is deleted, the students in the school are not deleted. This happens when a user create a school and students and delete the school immediately. Are there any workarounds for now? @Model final class School { var name: String @Relationship(deleteRule: .cascade, inverse: \Student.school) var students: [Student] = [] init(name: String) { self.name = name } } @Model final class Student { var fullName: String var school: School init(fullName: String, school: School) { self.fullName = fullName self.school = school } }
10
7
3.0k
Oct ’23
Why aren't changes to @Published variables automatically published on the main thread?
Given that SwiftUI and modern programming idioms promote asynchronous activity, and observing a data model and reacting to changes, I wonder why it's so cumbersome in Swift at this point. Like many, I have run up against the problem where you perform an asynchronous task (like fetching data from the network) and store the result in a published variable in an observed object. This would appear to be an extremely common scenario at this point, and indeed it's exactly the one posed in question after question you find online about this resulting error: Publishing changes from background threads is not allowed Then why is it done? Why aren't the changes simply published on the main thread automatically? Because it isn't, people suggest a bunch of workarounds, like making the enclosing object a MainActor. This just creates a cascade of errors in my application; but also (and I may not be interpreting the documentation correctly) I don't want the owning object to do everything on the main thread. So the go-to workaround appears to be wrapping every potentially problematic setting of a variable in a call to DispatchQueue.main. Talk about tedious and error-prone. Not to mention unmaintainable, since I or some future maintainer may be calling a function a level or two or three above where a published variable is actually set. And what if you decide to publish a variable that wasn't before, and now you have to run around checking every potential change to it? Is this not a mess?
9
0
3.6k
Nov ’23
Subscription State Persistence with new StoreKit SwiftUI API
App Purchase Validation and In-App Purchase Persistence with the older StoreKit APIs is complicated. I’m curious to learn whether the new StoreKit SwiftUI views and .subscriptionStatusTask modifier simplify the process — or ideally eliminates the need to implement complex Validation and persistence logic using AppStorage, Keychain or App Receipts. Any thoughts on this?
2
0
664
Nov ’23
Persist navigation paths in NavigationSplitView with NavigationStacks
I have an SwiftUI iOS app that uses TabView to display 4 different NavigationStacks. Each stack can be navigated into. To make this app work better on iPad OS I'd like to use a NavigationSplitView with a sidebar and a detail view. The sidebar contains a menu with the 4 items that are tabs on iOS. The detail view should contain individual NavigationStacks that should retain their view paths. After having played around with it a bit it seems to me that NavigationSplitView is not meant to be used that way. The detail view resets every time I select another menu item in the sidebar. I've tried retaining the individual navigation paths (as @States) in my root view and passing them into the individual NavigationStack when creating the detail view. However, it seems like NavigationSplitView is resetting the path whenever you switch to another menu item. Has anybody figured this out?
3
2
1.1k
Nov ’23
MapKit in List Breaks Top/Bottom Bar FadeIn/Out Effect
I've encountered a weird issue with the new Map for iOS 17. In my list, which includes a MapView among other elements, I've observed that with the new initializer, the top and bottom bars are persistently displayed. They don't hide and only appear when scrolling, as they should. This problem doesn't occur with the old, now-deprecated initializer. To illustrate this, I have two screenshots: one with the map enabled and the other with the map disabled, demonstrating the issue. Here is also my new Map code: struct MapListRowView: View { @Binding internal var location: LocationModel @State internal var user: Bool = true private var position: CLLocationCoordinate2D { .init(latitude: location.latitude, longitude: location.longitude) } private var isPad: Bool { UIDevice.current.userInterfaceIdiom == .pad ? true : false } var body: some View { Map(bounds: .init(minimumDistance: 1250)) { if user { UserAnnotation() } Annotation("", coordinate: position) { ZStack { Circle().fill().foregroundColor(.white).padding(1) Image(systemName: "mappin.circle.fill") .resizable() .foregroundColor(.indigo) }.frame(width: 20, height: 20).opacity(user ? .zero : 1.0) } } .frame(height: isPad ? 200 : 100) .cornerRadius(8) .listRowInsets(.init(top: -5, leading: .zero, bottom: -5, trailing: .zero)) .padding(.vertical, 5) .disabled(true) } }
3
1
644
Nov ’23
Auto Layout Constraint Conflict in SwiftUI When Tapping TextField
I am developing an iOS app using SwiftUI and have encountered an Auto Layout constraint conflict issue that appears when tapping on a TextField within a LoginView. I've tried several troubleshooting steps but haven't been able to resolve it. Error Message: Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "<NSLayoutConstraint:0x6000021298b0 'accessoryView.bottom' _UIRemoteKeyboardPlaceholderView:0x10460dd10.bottom == _UIKBCompatInputView:0x1059220e0.top (active)>", "<NSLayoutConstraint:0x60000217a620 'assistantHeight' SystemInputAssistantView.height == 45 (active, names: SystemInputAssistantView:0x10591ce60 )>", "<NSLayoutConstraint:0x60000217d090 'assistantView.bottom' SystemInputAssistantView.bottom == _UIKBCompatInputView:0x1059220e0.top (active, names: SystemInputAssistantView:0x10591ce60 )>", "<NSLayoutConstraint:0x60000217d040 'assistantView.top' V:[_UIRemoteKeyboardPlaceholderView:0x10460dd10]-(0)-[SystemInputAssistantView] (active, names: SystemInputAssistantView:0x10591ce60 )>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x60000217d040 'assistantView.top' V:[_UIRemoteKeyboardPlaceholderView:0x10460dd10]-(0)-[SystemInputAssistantView] (active, names: SystemInputAssistantView:0x10591ce60 )> This error appears in the console when I click on the TextField in my LoginView while running the code on a simulation. The app doesn't crash, but the console indicates there is a constraint conflict related to the keyboard. Here's my LoginView: struct LoginView: View { @StateObject var viewModel = LoginViewModel() var body: some View { NavigationStack { VStack { Spacer() Image("logo") .resizable() .scaledToFit() .frame(width: 150, height: 100) VStack { TextField("Enter your email", text: $viewModel.email) .autocapitalization(/*@START_MENU_TOKEN@*/.none/*@END_MENU_TOKEN@*/) .modifier(TextFieldModifier()) SecureField("Enter your password", text: $viewModel.password) .modifier(TextFieldModifier()) } Button { print("Show forgot password") } label: { Text("Forgot Password") .font(.footnote) .fontWeight(.semibold) .padding(.top) .padding(.trailing, 20) } .frame(maxWidth: .infinity, alignment: .trailing) Button { Task { try await viewModel.signIn() } } label: { Text("Login") .font(.subheadline) .fontWeight(.semibold) .foregroundColor(.white) .frame(width: 360, height: 44) .background(Color(.black)) .cornerRadius(8) } .padding(.vertical) HStack { Rectangle() .frame(width: (UIScreen.main.bounds.width / 2) - 40, height: 0.5) Text("OR") .font(.footnote) .fontWeight(.semibold) .foregroundColor(.gray) Rectangle() .frame(width: (UIScreen.main.bounds.width / 2) - 40, height: 0.5) } .foregroundColor(.gray) HStack { Image("facebook_logo") .resizable() .frame(width: 20, height: 20) Text("Continue with Facebook") .font(.footnote) .fontWeight(.semibold) .foregroundColor(Color(.systemBlue)) } .padding(.top, 8) Spacer() Divider() NavigationLink { AddEmailView() .navigationBarBackButtonHidden(true) } label: { HStack (spacing: 3) { Text("Don't have an account?") Text("Sign Up") .fontWeight(.semibold) } .font(.footnote) } .padding(.vertical, 16) } } } } #Preview { LoginView() } And my TextFieldModifier: struct TextFieldModifier: ViewModifier { func body(content: Content) ->some View { content .font(.subheadline) .padding(12) .background(Color(.systemGray6)) .cornerRadius(10) .padding(.horizontal, 24) .padding(.top) } } Attempts to Resolve: I've checked the TextFieldModifier for any potential issues but it seems standard. I've tried simplifying the view by removing other elements, but the issue persists. The issue seems to occur regardless of the simulator device or iOS version I use. Questions: What could be causing this Auto Layout constraint conflict in a SwiftUI app? Are there any known issues with SwiftUI's TextField and keyboard interactions that might lead to such constraints issues? Any suggestions on how to debug or resolve this constraint conflict?
3
3
2.9k
Nov ’23
arrowEdge of popoverTip not working anymore on iOS 17.1
In iOS 17.1 (and 17.2 beta), the arrowEdge parameter of the SwiftUI popoverTip doesn't work anymore. This code button .popoverTip(tip, arrowEdge: .bottom) looks like this on iOS 17.0 and like this on 17.1 and up. I checked permittedArrowDirections of the corresponding UIPopoverPresentationController (via the Memory Graph): It's .down on iOS 17.0 and .any (the default) on 17.1. It seems the parameter of popoverTip is not properly propagated to the popover controller anymore.
2
1
1.7k
Nov ’23
EditMode & EditButton not working in a way I expect
I have something that looks like: NavigationStack { List(self.items, id: \.self, selection: self.$selectedItems) { item in NavigationLink { ItemView(item: item) .environment(\.managedObjectContext, self.viewContext) } label: { LabelWithMenuView(object: item) { ptr in self.labelHandler(item: item, newName: ptr) } } } if self.editMode?.wrappedValue == .active { editButtons } else { TextField("Add Item", text: self.$newItem) .onSubmit { self.addItem() self.newItem = "" } .padding() } } #if os(iOS) .toolbar { EditButton() } .onChange(of: self.editMode?.wrappedValue) { old, new in print("editMode \(old) -> \(new)") } #endif With that layout, the edit button doesn't show up at all; if I put it as part of the List, it does show up, but the first click doesn't do anything; after that, it works, but the onChange handler doesn't show it getting changed, and the editButtons don't go away.
8
2
2.2k
Nov ’23
Xcode 15 Fault Message in Debug Console
Platform Late 2018 Intel 15” MacBook Pro macOS 15 Xcode 15, CLTools 15 Fault Message This fault message started after upgrading to macOS Sonoma 15. It only occurs on macOS targeted projects (not iOS). The fault occurs on projects using the TextField or TextEditor views. The projects build, test and run fine. FAULT: <NSRemoteView: 0x7f7f8ec34fe0 com.apple.TextInputUI.xpc.CursorUIViewService TUICursorUIViewService> determined it was necessary to configure <TUINSWindow: 0x7f7f8e91b490> to support remote view vibrancy Example The fault does not occur in UI Tests ContentView.txt FaultTestUITests.txt
5
9
1.8k
Dec ’23
Very annoying warnings using XCode and SwiftUI
I recently changed my old ancient MacBookPro for a MBAir 15" M2., mainly to upgrade Xcode and Swift to SwiftUI. But using Xcode 15.1, trying to update the preview, or trying to run the code I get bombarded by these warnings: managedappdistributiond unexpectedly quit findmylocated unexpectedly quit aegirposter unexpectedly quit. The warnings are so frequent that it stops me programming. Mind, I'm not a professional programmer, rather a very driven amateur, but I don't think this this is what is meant by offering a great API. Can someone please help me get rid off all this irritating stuff.
17
11
2.9k
Dec ’23
SwiftUI creating MapCameraPosition from CLLocationManager initialiser/self error when trying to tie them? (see code)
Trying to use new Swift @Observable to monitor GPS position within SwiftUI content view. But how do I tie the latest locations to the SwiftUI Map's mapCameraPosition? Well ideally the answer could cover: How to fix this error - So get map tracking along with the User Position, but also How to include facility to turn on/off the map moving to track the user position (which I'll need to do next). So could be tracking, then disable, move map around and have a look at things, then click button to start syncing the mapcameraposition to the GPS location again Refer to error I'm embedded in the code below. import SwiftUI import MapKit @Observable final class NewLocationManager : NSObject, CLLocationManagerDelegate { var location: CLLocation? = nil private let locationManager = CLLocationManager() func startCurrentLocationUpdates() async throws { if locationManager.authorizationStatus == .notDetermined { locationManager.requestWhenInUseAuthorization() } for try await locationUpdate in CLLocationUpdate.liveUpdates() { guard let location = locationUpdate.location else { return } self.location = location } } } struct ContentView: View { var newlocationManager = NewLocationManager() @State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion( center: newlocationManager.location?.coordinate ?? <#default value#>, span: MKCoordinateSpan(latitudeDelta: 0.25, longitudeDelta: 0.25) )) // GET ERROR: Cannot use instance member 'newlocationManager' within property initializer; property initializers run before 'self' is available var body: some View { ZStack { Map(position: $cameraPosition) Text("New location manager: \(newlocationManager.location?.description ?? "NIL" )") // works } .task { try? await newlocationManager.startCurrentLocationUpdates() } } } #Preview { ContentView() }
2
0
1.4k
Jan ’24
matchedGeometryEffect flickers in a TabView
I tried building the View from this section, but when there is a List on the second tab, the animation performed by the matchedGeometryEffect does not work as intended. This video shows how the transition works with Text("Second Tab") as the second tab. Everything looks fine. But when I replace the Text with a List, the transition flickers and does not look smooth anymore. List { Text("The Scarlet Letter") Text("Moby-Dick") Text("Little Women") Text("Adventures of ") } Here is the code for the app. import SwiftUI @main struct MyWatchApp: App { @Namespace var library @State var pageNumber = 0 private let bookIcon = "bookIcon" var body: some Scene { WindowGroup { NavigationStack { TabView(selection: $pageNumber) { VStack { Image(systemName: "books.vertical.fill") .imageScale(.large) .matchedGeometryEffect( id: bookIcon, in: library, properties: .frame, isSource: pageNumber == 0) Text("Books") } .tag(0) Text("Second Tab").tag(1) } .tabViewStyle(.verticalPage) .toolbar { ToolbarItem(placement: .topBarLeading) { Image(systemName: "books.vertical.fill") .matchedGeometryEffect( id: bookIcon, in: library, properties: .frame, isSource: pageNumber != 0) } } } } } }
1
2
926
Jan ’24
EnvironmentObject Causes SwiftUI App to Crash When Launched in the Background
I recently encountered a difficult-to-diagnose bug in an app that I'm working on, and I thought I would share it with the Apple Developer community. The app that I'm working on is an iOS app that uses Core Location's Visit Monitoring API, and it is essential that the app is able to process incoming visits while running in the background. However, after real-world testing, I discovered several crash reports which were difficult to understand, as SwiftUI symbols are not symbolicated on debug builds. Eventually I discovered that the app was crashing when calling an @EnvironmentObject property of the root ContentView from that view's body when the app was launched directly into the background from not running at all. After creating a small test app to isolate the problem, I discovered that any environment object declared in the App struct and referenced from the root ContentView causes the crash, with the exception message: "Fatal error: No ObservableObject of type ArbitraryEnvObject found. A View.environmentObject(_:) for ArbitraryEnvObject may be missing as an ancestor of this view." It seems that when a SwiftUI app is launched in the background, the ContentView's body is executed, but the environment is not initialized. I searched through as much documentation as I could, but could not find any information about how this should be handled, so I think it's a bug in SwiftUI. I have filed a Feedback Assistant bug report. The current workaround is to convert my ObservableObject into an object that conforms to the new @Observable protocol, add it to the scene as an Environment Value with the .environment(_:) modifier rather than the .environmentObject(_:) modifier, and declare the @Environment property on the view as optional. The object will still be missing when the app is launched in the background, but the optional property can be handled safely to prevent a crash. Attached to this post is a sample project that demonstrates the issue and the workaround. And finally, I'd like to hear from anyone who knows more about the expected behavior of background launches of SwiftUI apps, and whether or not there's something I should be doing completely differently. I'm not able to directly attach a zip archive to this post, so here's an iCloud link to the sample project: BackgroundEnvObjCrash.zip
6
2
4k
Jan ’24
SwiftUI view not updated after SwiftData change through CloudKit
A SwiftUI view is displaying a SwiftData model object that's being updated on another device, using CloudKit. The update arrives through CloudKit and the view is correctly updated. However, when the view is not displaying the model object directly, but in a nested view, this nested view is NOT updated. Why not? Is this a bug? Or is it just me, forgetting about some elementary detail? A workaround (that I definitely don't like!) is to put a dummy SwiftData query in the nested view. Even when the dummy query result is never used, the view now IS updated correctly. Why? The code below is mostly Xcode's standard template for a SwiftUI+SwiftData+CloudKit app, modified to use a String property i.s.o. a Date, and to be able to edit that name in a Textfield. The ContentView: struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in @Bindable var item = item NavigationLink { VStack(alignment: .leading) { // item details in same view TextField(item.name, text: $item.name) .textFieldStyle(.roundedBorder) .padding() .background(.red.opacity(0.5)) // item details in nested view ItemDetailView(item: item) .padding() .background(.yellow.opacity(0.5)) Spacer() } } label: { Text(item.name) } } .onDelete(perform: deleteItems) } #if os(macOS) .navigationSplitViewColumnWidth(min: 180, ideal: 200) #endif .toolbar { #if os(iOS) ToolbarItem(placement: .navigationBarTrailing) { EditButton() } #endif ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } detail: { Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(name: "item") modelContext.insert(newItem) } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } } The nested ItemDetailView: struct ItemDetailView: View { @Bindable var item: Item // dummy query to force view updates triggered by CloudKit // @Query private var items: [Item] var body: some View { TextField(item.name, text: $item.name) .textFieldStyle(.roundedBorder) } } The result:
3
3
1.2k
Jan ’24