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.
How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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.
According to docs, .focusedObject() usage should be moved to .focusedValue() when migrating to @Observable, but there is no .focusedSceneValue() overload that accepts Observable like with .focusedValue(). So how are we supposed migrate .focusedSceneObject() to @Observable?
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
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?
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
}
}
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?
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?
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?
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)
}
}
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?
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.
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.
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
I have a scroll view that scrolls horizontally and one of my users is asking that it respond to their scroll wheel without them having to use the shift key. Is there some way to do this natively? If not, how can I listen for the scroll wheel events in swiftUI and make my scroll wheel scroll to respond to them?
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.
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()
}
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)
}
}
}
}
}
}
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
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: