I've run into a problem that has been giving me fits for a while and have yet to be able to find a solution. We have a Catalyst app that uses a three-pane UISplitView. The middle and third panes show the navigation bar of the UINavigationController hosted in each pane.
However, when building under Xcode 15, the navigation bar is not shown in the middle pane when running under macOS 14. It is shown, as expected, when the app is run under prior versions of macOS. It also appears as it should under macOS 14 if the app is built with Xcode 14.
If you push another view controller onto the navigation controller's stack with the animate flag set to true, the navigation bar will appear. When you go back to the root controller, the navigation bar is present as it should be. However, if you push the controller with the animate flag set to false, the navigation bar does not appear.
I've been able to reproduce this in an isolated test app with just the relevant components. The first screenshot at the end is from a test app that illustrates the problem. The second screenshot shows what it should look like (and does look like under macOS 13).
It should be noted that UINavigationBar.appearance().preferredBehavioralStyle = .pad is set.
If any Apple folk would kindly like to look into this, I created a feedback for it: FB13260893. The feedback entry has a sample app, screenshots, and even a screen recording demonstrating the problem.
Has anyone else run into this or does anyone have any suggestions for a fix/workaround?
Thanks,
Kevin
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm working on a NavigationStack based app. Somewhere I'm using:
@Environment(\.dismiss) private var dismiss
and when trying to navigate to that view it gets stuck.
I used Self._printChanges() and discovered the environment variable dismiss is changing repeatedly. Obviously I am not changing that variable explicitly. I wasn't able to reproduce this in a small project so far, but does anybody have any idea what kind of thing I could be doing that might be causing this issue?
iOS 17.0.3
Prior to macOS 14, a Catalyst app could present a UIAlertController as a popover, just as you can on the iPad. While this still works on the iPad, the presentation on macOS now uses the same style as the iPhone.
The UIAlertController's popoverPresentationController property is always nil, no matter how it is configured.
Doe anyone know of a way to restore the prior behavior under Sonoma?
I am using public struct ShareLink<Data, PreviewImage, PreviewIcon, Label> : View where Data : RandomAccessCollection, PreviewImage : Transferable, PreviewIcon : Transferable, Label : View, Data.Element : Transferable {}
And it is generating entitlement errors and not working reliably ( will transfer 1-3 items, but not 4+ ; will not work a second time)
Error is:
Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)}>
Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
Code is
import SwiftUI
var images = Array<Image?>(repeating: nil , count: 200);
struct ShareTestGContentView: View {
let columns = [GridItem(.fixed(165)), GridItem(.fixed(165))]
private let twoColumnGrid = [ GridItem(.flexible(minimum: 40), spacing: 2), GridItem(.flexible(minimum: 40), spacing: 2) ]
@State var selected = Set()
var body: some View {
topSection()
ScrollView {
LazyVGrid(columns: twoColumnGrid, spacing: 2) { // columns: [GridItem(.flexible())]) {
ForEach(1...100, id: \.self) { idx in
var cr = ( selected.contains(idx) ? 16.0 : 0 )
var lw = ( selected.contains(idx) ? 8.0 : 0 )
VStack{
Button(action: {
if selected.contains(idx) {
selected.remove(idx); cr = 0.0; lw = 0.0
} else {
selected.insert(idx); cr = 16.0; lw = 8.0
}
} , label: {
AsyncImage(url :URL(string: "https://picsum.photos/800/800?\(idx)")) { image in
let _ = ( images[idx] = image.image )
image.image
}.frame(width: boxHalf,height:boxHalf).drawingGroup()
})
}.overlay(
RoundedRectangle(cornerRadius: cr).stroke(Color.yellow, lineWidth: lw)
).drawingGroup()
}
}
}
}
func topSection() -> some View {
let imgarray = selected.compactMap { images[$0] }
return HStack {
ShareLink("",items: imgarray) { img in
SharePreview("images", image: Image(systemName: "captions.bubble.fill"))
}
}
}
}
#Preview {
ShareTestGContentView()
}
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.
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?
My App development language is only Arabic. I am using textField to Login User, whenever user long pressed, ToolTip showed up. Problem is with tool tip text it is flipped. My device language is English
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?
After updating to Mac OS Sonoma, we have encountered compatibility issues with our iPad-designed application, specifically with the AirPrint functionality, when it is run on MacOS. The AirPrint feature stopped working properly through UIPrintInteractionController.shared.
We have noticed that when we compile the application using Catalyst, the AirPrint functionality is restored and works as expected. However, this solution is not viable for us due to the restrictions associated with the frameworks we are utilizing.
We are seeking alternative solutions, and any help or guidance would be highly appreciated to resolve this issue and ensure a seamless and uninterrupted user experience in our application.
STEPS TO REPRODUCE
Create an app for ipad with just a button and this code
var str = "TEST"
let printInfo = UIPrintInfo(dictionary:nil)
printInfo.outputType = .general
printInfo.jobName = "Report"
printInfo.orientation = .portrait
let printController = UIPrintInteractionController.shared
printController.printInfo = printInfo
printController.showsNumberOfCopies = false
printController.showsPageRange = false
printController.showsNumberOfCopies = false
let formatter = UIMarkupTextPrintFormatter(markupText: str)
formatter.contentInsets = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)
printController.printFormatter = formatter
printController.present(animated: true, completionHandler: nil)
2.Run it on a MacOS with Sonoma, there is no error on console or anything but it don't work.
-If you run it with Catalyst it just works when adding the Printing permission of App Sandbox in Signing & Capabilities.
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
}
}
It appears that we are not able to reorder rows in our tables when running our iOS/iPadOS app under Mac Catalyst. It appears that all the delegate methods are returning true indicating the row can be moved and edited. The reordering handles appear in editing move and the row can be moved around (also using drag and drop) but the user interface is not indicating that the row can be dropped to be reordered. It's as if the proposed destination path is being rejected. I tried setting up that delegate method (thinking that maybe the default for that is messed up on Mac Catalyst) but it had no effect. Every table in our system performs this way.
Here is a link to an example video that shows the table view not working:
https://onsongapp.s3.amazonaws.com/Reordering%20Example.mp4
Please advise if there is something else that needs to be implemented or changed for Mac Catalyst to properly handle table cell reordering.
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.