Step to reproduce:
I installed the example project on this page
I opened the Popover Tip View example
And clicked on the icon that should output to the console and invalidate the tip
Image(systemName: "wand.and.stars")
.imageScale(.large)
.popoverTip(popoverTip)
.onTapGesture {
print("test")
// Invalidate the tip when someone uses the feature.
popoverTip.invalidate(reason: .actionPerformed)
}
On version 17 with Tip presented, when I click on the button, I immediately get the output to the console and the tip disappears. On version 18, when I click on a button, the tip just disappears, it feels like it just overlaps everything and the clicks don't go any further. If anything the project is the same as in the example, I have only lowered the minimum version to 17.4.
As I understand there is a bug in iOS version 18, hence I have a question if there are ways to fix this?
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
When using my app's complications with either Siri Intents or App Intents after syncing .watchface files, the complications appear without names in the iOS Watch app's complication picker. This leads to complications showing as blank entries without previews in the native watch app selector.
I'm using WidgetKit to create Watch complications with both approaches: AppIntents and Siri Intents.
We've tried multiple approaches with our WidgetKit watch complications:
Switching between IntentConfiguration and StaticConfiguration
Using different naming conventions for kind strings
Ensuring display names are properly set
Testing across different watchOS versions
But the result is always the same: after syncing .watchface files, our complications appear unnamed in the Watch app's complication picker.
Is this a known limitation with .watchface syncing, a bug in the current implementation, or is there a specific requirement we're missing to maintain complication names during the sync process?
I released an app for iPhone (and it's could be downloaded for iPad also), and now I developered another app for iPad version with the same code and logic but I modified the layout to fit bigger screen and make better user experience and appearance.
Howevert the app review rejected my release due to the duplicate content, how can I solve it?
Topic:
UI Frameworks
SubTopic:
General
In the new beta, NSStatusNone et. al. are either missing or not rendered.
Example screenshot is from Xcode, but other apps are also affected.
Filed as FB16822441
Topic:
UI Frameworks
SubTopic:
AppKit
Hello Apple Developer Community,
I’m facing a recurring issue in my SwiftUI iOS app where a specific view fails to reload correctly after saving edits and navigating back to it. The failure happens consistently post-save, and I’m looking for insights from the community.
🛠 App Overview
Purpose
A SwiftUI app that manages user-created data, including images, text fields, and completion tracking.
Tech Stack:
SwiftUI, Swift 5.x
MSAL for authentication
Azure Cosmos DB (NoSQL) for backend data
Azure Blob Storage for images
Environment:
Xcode 15.x
iOS 17 (tested on iOS 18.2 simulator and iPhone 16 Pro)
User Context:
Users authenticate via MSAL.
Data is fetched via Azure Functions, stored in Cosmos DB, and displayed dynamically.
🚨 Issue Description
🔁 Steps to Reproduce
Open a SwiftUI view (e.g., a dashboard displaying a user’s saved data).
Edit an item (e.g., update a name, upload a new image, modify completion progress).
Save changes via an API call (sendDataToBackend).
The view navigates back, but the image URL loses its SAS token.
Navigate away (e.g., back to the home screen or another tab).
Return to the view.
❌ Result
The view crashes, displays blank, or fails to load updated data.
SwiftUI refreshes text-based data correctly, but AsyncImage does not.
Printing the image URL post-save shows that the SAS token (?sv=...) is missing.
❓ Question
How can I properly reload AsyncImage after saving, without losing the SAS token?
🛠 What I’ve Tried
✅ Verified JSON Structure
Debugged pre- and post-save JSON.
Confirmed field names match the Codable model.
✅ Forced SwiftUI to Refresh
Tried .id(UUID()) on NavigationStack:
NavigationStack {
ProjectDashboardView()
.id(UUID()) // Forces reinit
}
Still fails intermittently.
✅ Forced AsyncImage to Reload
Tried appending a UUID() to the image URL:
AsyncImage(url: URL(string: "\(imageUrl)?cacheBust=\(UUID().uuidString)"))
Still fails when URL query parameters (?sv=...) are trimmed.
I’d greatly appreciate any insights, code snippets, or debugging suggestions! Let me know if more logs or sample code would help.
Thanks in advance!
In my app, I have a ShareLink that attempts to share a movie.
struct MovieTransferable: Transferable {
let url: URL
let writeMovie: (URL) -> ()
static var transferRepresentation: some TransferRepresentation {
DataRepresentation(
exportedContentType: .movie,
exporting: {
(movie) in
// Write the movie into documents.
movie.writeMovie(movie.url)
return try! Data(contentsOf: movie.url)
})
FileRepresentation(
exportedContentType: .movie,
exporting: {
(movie) in
// Write the movie into documents.
movie.writeMovie(movie.url)
return SentTransferredFile(movie.url)
})
}
}
The ShareLink works if you try to share the movie with the Photos app, Air Drop, and iMessage. If I share to WhatsApp, the movie shows up as empty (zero length), but there's a movie. If I share to Discord, the movie is not displayed at all (only the comment). Instagram posts a dialog saying it won't allow movies and to use the app (why are they even in the ShareLink option for movies?). YouTube processes for a bit and then does nothing (no upload).
Are there things that I can do to make the Transferable accepted at more of the end points? It's at fps 30 and I've tried most of the available codec's. The size is the same as the iPhone's screen, so the aspect ratio is a bit odd. However, if I go directly to the app (Discord, etc...) upload from my phone works fine.
Any help would be appreciated to make this more viable.
The main function of this code is that when I click on the link within the TextView, the TextView will respond to the event, while when clicking on other places, the TextView will not respond to the event.
I want to know how to use TextKit2 to achieve the same functionality as the following code?
class MyTextView: UITextView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
var location = point
location.x -= textContainerInset.left
location.y -= textContainerInset.top
let characterIndex = layoutManager.characterIndex(for: location, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
if characterIndex < textStorage.length, characterIndex >= 0 {
if let _ = textStorage.attribute(.link, at: characterIndex, effectiveRange: nil) {
return self
}
}
return nil
}
}
I haven't found a method similar to that in Textkit1 within Textkit2. I'm looking forward to everyone's guidance.
Simple master screen with list, NavigationLink to editable detail view.
I want edits on the detail screen to update to the master list "cars" variable and the list UI.
On the detail view, if I edit one field and exit the field, the value reverts to the original value. Why?
If I edit one field, don't change focus and hit the back button. The master list updates. This is what I want, but I can only update 1 field because of problem #1. Should be able to edit all the fields.
If I implement the == func in the Car struct, then no updates get saved. Why?
struct Car: Hashable, Equatable {
var id: UUID = UUID()
var make: String
var model: String
var year: Int
// static func == (lhs: Car, rhs: Car) -> Bool {
// return lhs.id == rhs.id
// }
}
struct ContentView: View {
@State private var cars: [Car]
init() {
cars = [
Car(make: "Toyota", model: "Camry", year: 2020),
Car(make: "Honda", model: "Civic", year: 2021),
Car(make: "Ford", model: "Mustang", year: 2022),
Car(make: "Chevrolet", model: "Malibu", year: 2023),
Car(make: "Nissan", model: "Altima", year: 2024),
Car(make: "Kia", model: "Soul", year: 2025),
Car(make: "Volkswagen", model: "Jetta", year: 2026)
]
}
var body: some View {
NavigationStack {
VStack {
ForEach($cars, id: \.self) { $car in
NavigationLink(destination: CarDetailView(car: $car)){
Text(car.make)
}
}
}
}
}
}
struct CarDetailView: View {
@Binding var car: Car
var body: some View {
Form {
TextField("Make", text: $car.make)
TextField("Model", text: $car.model)
TextField("Year", value: $car.year, format: .number)
}
}
}
I have an App that builds for iOS, iPadOS, macOS and Apple TV, which was last released to all the App Stores in April. Preferences/settings are handled by the App itself except for the Apple TV variant, where I use a Settings bundle. This worked fine until tvOS 15.0, where it appears that tvOS is not updating the value of the App’s settings from NSUserDefaults when the Settings App opens. I have been working on this problem off and on for the last week and am at wits end.
I’ve searched WWDC videos looking for a clue, there must be some simple change I cannot see. I’ve made clean projects for iOS and tvOS, and using the identical OBJ-C code and Settings plist entries, the iOS version works perfectly, the tvOS version fails in the simulator and on the device. I am not trying to synchronize Settings across devices, just persist across restarts on a single device.
My code stores data correctly in NSUserDefaults, it simply seems that tvOS Settings App is not reading values from there for display, nor writing changes that the user makes from Settings back to user defaults. None of the types in the test projects work: TexField, Switch, Title.
The test code is so simple I hesitate to include it, but the code and the NSUserDefaults key identifiers do match. This code will preset my App’s version number for Settings to display in iOS 15 but not tvOS 15. It used to work in tvOS 14:
<key>DefaultValue</key>
<string>DefaultVersionValue</string>
<key>Type</key>
<string>PSTitleValueSpecifier</string>
<key>Title</key>
<string>Version</string>
<key>Key</key>
<string>VersionKey</string>
</dict>
``` NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud registerDefaults:@{
@"TextFieldKey" : @"TextFieldValue",
@"VersionKey" : @"VersionValue"
}];
[ud setObject:@"3.14" forKey:@"VersionKey"];
Any idea? Many thanks.
Hello, I have encountered a question that I hope to receive an answer to. Currently, I am working on a music project for Mac Catalyst and need to enable music files such as FLAC to be opened by right clicking to view my Mac Catalyst app. But currently, I have encountered a problem where I can see my app option in the right-click open mode after debugging the newly created macOS project using the following configuration. But when I created an iOS project and converted it to a Mac Catalyst app, and then modified the info.plist with the same configuration, I couldn't see my app in the open mode after debugging. May I ask how to solve this problem? Do I need to configure any permissions or features in the Mac Catalyst project? I have been searching for a long time but have not found a solution regarding it. Please resolve it, thank you.
Here is the configuration of my macOS project:
CFBundleDocumentTypes
CFBundleTypeExtensions
flac
CFBundleTypeIconSystemGenerated
1
CFBundleTypeName
FLAC Audio File
CFBundleTypeRole
Viewer
LSHandlerRank
Default
Note: Sandbox permissions have been enabled for both the macOS project and the iOS to Mac Catalyst project. The Mac Catalyst project also has additional permissions for com. apple. security. files. user taught. read write
After updating to Sonoma, the following is logged in the Xcode console when an editable text field becomes key. This doesn't occur on any text field, but it seems to happen when the text field is within an NSPopover or an NSSavePanel.
ViewBridge to RemoteViewService Terminated: Error Domain=com.apple.ViewBridge Code=18 "(null)" UserInfo={com.apple.ViewBridge.error.hint=this process disconnected remote view controller -- benign unless unexpected, com.apple.ViewBridge.error.description=NSViewBridgeErrorCanceled}
What does this mean?
Topic:
UI Frameworks
SubTopic:
AppKit
Hello, community,
I'm using an HTML editor in a .NET MAUI application running on macOS, and I'm encountering some unexpected behavior during text editing:
Double-click text selection disappears after approximately one second.
Styles randomly revert or are applied to the wrong text unexpectedly.
It appears to be related to macOS spell checking. When using editable elements (, or with contenteditable), the system enables spell checking by default.
During this, MAUI attempts to communicate with a system process:
com.apple.TextInput.rdt, which is not running, leading to repeated errors like:
Error Domain=NSCocoaErrorDomain Code=4099
"The connection to service named com.apple.TextInput.rdt was invalidated: failed at lookup with error 3 - No such process."
Question:
What is com.apple.TextInput.rdt, and why might it not be running?
Thank you for any help!
UIKit and SwiftUI each have their own strengths and weaknesses:
UIKit: More performant (e.g., UICollectionView).
SwiftUI: Easier to create shiny UI and animations.
My usual approach is to base my project on UIKit and use UIHostingController whenever I need to showcase visually rich UI or animations (such as in an onboarding presentation).
So far, this approach has worked well for me—it keeps the project clean while solving performance concerns effectively.
However, I was wondering: Has anyone tried the opposite approach?
Creating a project primarily in SwiftUI, then embedding UIKit when performance is critical.
If so, what has your experience been like? Would you recommend this approach?
I'm considering this for my next project but am unsure how well it would work in practice.
I want to show a view, where the user can add or remove items shown as icons, which are sorted in two groups: squares and circles.
When there are only squares, they should be shown in one row:
[] [] []
When there are so many squares that they don’t fit horizontally, a (horizontal) scrollview will be used, with scroll-indicator always shown to indicate that not all squares are visible.
When there are only circles, they also should be shown in one row:
() () ()
When there are so many circles that they don’t fit horizontally, a (horizontal) scrollview will be used, with scroll-indicator always shown to indicate that not all circles are visible.
When there a few squares and a few circles, they should be shown adjacent in one row:
[] [] () ()
When there are so many squares and circles that they don’t fit horizontally, they should be shown in two rows, squares on top, circles below:
[] [] []
() () ()
When there are either too many squares or too many circles (or both) to fit horizontally, one common (horizontal) scrollview will be used, with scroll-indicator always shown to indicate that not all items are visible.
I started with ViewThatFits: (see first code block)
{
let squares = HStack {
ForEach(model.squares, id: \.self) { square in
Image(square)
}
}
let circles = HStack {
ForEach(model.circles, id: \.self) { circle in
Image(circle)
}
}
let oneLine = HStack {
squares
circles
}
let twoLines = VStack {
squares
circles
}
let scrollView = ScrollView(.horizontal) {
twoLines
}.scrollIndicators(.visible)
ViewThatFits(in: .horizontal) {
oneLine
twoLines
scrollView.clipped()
}
}
While this works in general, it doesn’t animate properly.
When the user adds or removes an image the model gets updated, (see second code block)
withAnimation(Animation.easeIn(duration: 0.25)) {
model.squares += image
}
and the view animates with the existing images either making space for a new appearing square/circle, or moving together to close the gap where an image disappeared.
This works fine as long as ViewThatFits returns the same view.
However, when adding 1 image leads to ViewThatFits switching from oneLine to twoLines, this switch is not animated. The circles jump to the new position under the squares, instead of sliding there.
I searched online for a solution, but this seems to be a known problem of ViewThatFits. It doesn't animate when it switches...
(tbc)
The issue I'm facing arise when using a lazyvstack within a navigationstack. I want to use the pinnedViews: .sectionHeaders feature from the lazyStack to display a section header while rendering the content with a scrollview. Below is the code i'm using and at the end I share a sample of the loop issue:
struct SProjectsScreen: View {
@Bindable var store: StoreOf<ProjectsFeature>
@State private var searchText: String = ""
@Binding var isBotTabBarHidden: Bool
@Environment(\.safeArea) private var safeArea: EdgeInsets
@Environment(\.screenSize) private var screenSize: CGSize
@Environment(\.dismiss) var dismiss
private var isLoading : Bool {
store.projects.isEmpty
}
var body: some View {
NavigationStack(path:$store.navigationPath.sending(\.setNavigationPath)) {
ScrollView(.vertical){
LazyVStack(spacing:16,pinnedViews: .sectionHeaders) {
Section {
VStack(spacing:16) {
if isLoading {
ForEach(0..<5,id:\.self) { _ in
ProjectItemSkeleton()
}
}
else{
ForEach(store.projects,id:\._id) { projectItem in
NavigationLink(value: projectItem) {
SProjectItem(project: projectItem)
.foregroundStyle(Color.theme.foreground)
}
.simultaneousGesture(TapGesture().onEnded({ _ in
store.send(.setCurrentProjectSelected(projectItem.name))
}))
}
}
}
} header: {
VStack(spacing:16) {
HStack {
Text("Your")
Text("Projects")
.fontWeight(.bold)
Text("Are Here!")
}
.font(.title)
.frame(maxWidth: .infinity,alignment: .leading)
.padding(.horizontal,12)
.padding(.vertical,0)
HStack {
SSearchField(searchValue: $searchText)
Button {
} label: {
Image(systemName: "slider.horizontal.3")
.foregroundStyle(.white)
.fontWeight(.medium)
.font(.system(size: 24))
.frame(width:50.66,height: 50.66)
.background {
Circle().fill(Color.theme.primary)
}
}
}
}
.padding(.top,8)
.padding(.bottom,16)
.background(content: {
Color.white
})
}
}
}
.scrollIndicators(.hidden)
.navigationDestination(for: Project.self) { project in
SFoldersScreen(project:project,isBotTabBarHidden: $isBotTabBarHidden)
.toolbar(.hidden)
}
.padding(.horizontal,SScreenSize.hPadding)
.onAppear {
Task {
if isLoading{
do {
let projectsData = try await ProjectService.Shared.getProjects()
store.send(.setProjects(projectsData))
}
catch{
print("error found: ",error.localizedDescription)
}
}
}
}
.refreshable {
do {
let projectsData = try await ProjectService.Shared.getProjects()
store.send(.setProjects(projectsData))
}
catch{
print("error found: ",error.localizedDescription)
}
}
}.onChange(of: store.navigationPath, { a, b in
print("Navigation path changed:", b)
})
}
}
I'm using tca library for managing states so this is my project feature reducer:
import ComposableArchitecture
@Reducer
struct ProjectsFeature{
@ObservableState
struct State: Equatable{
var navigationPath : [Project] = []
var projects : [Project] = [
]
var currentProjectSelected : String?
}
enum Action{
case setNavigationPath([Project])
case setProjects([Project])
case setCurrentProjectSelected(String?)
case popNavigation
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .setNavigationPath(let navigationPath):
state.navigationPath = navigationPath
return .none
case .setProjects(let projects):
state.projects = projects
return .none
case .setCurrentProjectSelected(let projectName):
state.currentProjectSelected = projectName
return .none
case .popNavigation:
if !state.navigationPath.isEmpty {
state.navigationPath.removeLast()
}
state.currentProjectSelected = nil
return .none
}
}
}
Hello everyone, I'm developing a radio app and I want to add CarPlay. Before starting the program I requested all the necessary permissions and they were accepted. Now when I run the app, emulate CarPlay and try to access the app, it crashes and gives me this log:
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Application does not implement CarPlay template application lifecycle methods in its scene delegate.'
*** First throw call stack:
(
0 CoreFoundation 0x00000001804b70ec __exceptionPreprocess + 172
1 libobjc.A.dylib 0x000000018008ede8 objc_exception_throw + 72
2 CoreFoundation 0x00000001804b6ffc -[NSException initWithCoder:] + 0
3 CarPlay 0x00000001bc830ee8 -[CPTemplateApplicationScene _deliverInterfaceControllerToDelegate] + 704
4 CarPlay 0x00000001bc82fa60 __64-[CPTemplateApplicationScene initWithSession:connectionOptions:]_block_invoke.4 + 116
5 CoreFoundation 0x00000001803e9aec CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER + 120
6 CoreFoundation 0x00000001803e9a24 ___CFXRegistrationPost_block_invoke + 84
7 CoreFoundation 0x00000001803e8f14 _CFXRegistrationPost + 404
8 CoreFoundation 0x00000001803e88f0 _CFXNotificationPost + 688
9 Foundation 0x0000000180ee2350 -[NSNotificationCenter postNotificationName:object:userInfo:] + 88
10 UIKitCore 0x0000000184f0a8e4 +[UIScene _sceneForFBSScene:create:withSession:connectionOptions:] + 1152
11 UIKitCore 0x0000000185aa445c -[UIApplication _connectUISceneFromFBSScene:transitionContext:] + 808
12 UIKitCore 0x0000000185aa470c -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 304
13 UIKitCore 0x0000000185573c08 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 260
14 FrontBoardServices 0x0000000187994ce4 __95-[FBSScene _callOutQueue_didCreateWithTransitionContext:alternativeCreationCallout:completion:]_block_invoke + 260
15 FrontBoardServices 0x00000001879950a4 -[FBSScene _callOutQueue_coalesceClientSettingsUpdates:] + 60
16 FrontBoardServices 0x0000000187994b64 -[FBSScene _callOutQueue_didCreateWithTransitionContext:alternativeCreationCallout:completion:] + 408
17 FrontBoardServices 0x00000001879c1d50 __93-[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:]_block_invoke.156 + 216
18 FrontBoardServices 0x00000001879a1618 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 160
19 FrontBoardServices 0x00000001879c0220 -[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:] + 388
20 libdispatch.dylib 0x0000000103e127b8 _dispatch_client_callout + 16
21 libdispatch.dylib 0x0000000103e163bc _dispatch_block_invoke_direct + 388
22 FrontBoardServices 0x00000001879e4b58 FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK + 44
23 FrontBoardServices 0x00000001879e4a34 -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 196
24 FrontBoardServices 0x00000001879e4b8c -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 24
25 CoreFoundation 0x000000018041b324 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 24
26 CoreFoundation 0x000000018041b26c __CFRunLoopDoSource0 + 172
27 CoreFoundation 0x000000018041a9d0 __CFRunLoopDoSources0 + 232
28 CoreFoundation 0x00000001804150b0 __CFRunLoopRun + 788
29 CoreFoundation 0x0000000180414960 CFRunLoopRunSpecific + 536
30 GraphicsServices 0x0000000190183b10 GSEventRunModal + 160
31 UIKitCore 0x0000000185aa2b40 -[UIApplication _run] + 796
32 UIKitCore 0x0000000185aa6d38 UIApplicationMain + 124
33 SwiftUI 0x00000001d1e2eab4 $s7SwiftUI17KitRendererCommon33_ACC2C5639A7D76F611E170E831FCA491LLys5NeverOyXlXpFAESpySpys4Int8VGSgGXEfU_ + 164
34 SwiftUI 0x00000001d1e2e7dc $s7SwiftUI6runAppys5NeverOxAA0D0RzlF + 84
35 SwiftUI 0x00000001d1b70c8c $s7SwiftUI3AppPAAE4mainyyFZ + 148
36 streamz.debug.dylib 0x0000000106148e98 $s7streamz7StreamzV5$mainyyFZ + 40
37 streamz.debug.dylib 0x0000000106148f48 __debug_main_executable_dylib_entry_point + 12
38 dyld 0x00000001032d9410 start_sim + 20
39 ??? 0x000000010301a274 0x0 + 4345406068
I also get this error in the 'App' protocol:
Thread 1: "Application does not implement CarPlay template application lifecycle methods in its scene delegate."
If you need anything specific to figure out what it's about, I'll be happy to help.
When trying to debug a mysterious app crash pointing to some layoutIfNeeded() method call, me and my QA team member reduced it to this sample app.
struct ContentView: View {
@State var isPresented = false
var body: some View {
VStack {
Button {
isPresented = true
} label: {
Text("show popover")
}
.popover(isPresented: $isPresented) {
Text("hello world")
}
}
.padding()
}
}`
This code crashes on his iPad iOS 18.1.0 22B5034E with EXC_BAD_ACCESS error. It is not reproducible on simulator or on device with iOS 18.2 or iOS 17.
Is this a known issue? Are there any known workarounds? I've found similar posts here
https://developer.apple.com/forums/thread/769757
https://developer.apple.com/forums/thread/768544
But they are about more specific cases.
I've been thinking a lot about how navigation and presentation are managed in SwiftUI, and I wanted to propose an idea for a more streamlined approach using environment values. Right now, handling navigation can feel fragmented — especially when juggling default NavigationStack, modals, and tab selections.
What if SwiftUI provided a set of convenience environment values for these common actions?
Tabs
@Environment(\.selectedTab) var selectedTab
@Environment(\.selectTab) var selectTab
selectedTab: Read the current tab index
selectTab(index: Int): Programmatically switch tabs
Stack Navigation
@Environment(\.stackCount) var stackCount
@Environment(\.push) var push
@Environment(\.pop) var pop
@Environment(\.popToRoot) var popToRoot
stackCount: Read how many views are in the navigation stack
push(destination: View): Push a new view onto the stack
pop(last: Int = 1): Pop the last views
popToRoot(): Return to the root view
Modals
@Environment(\.sheet) var sheet
@Environment(\.fullScreenCover) var fullScreenCover
@Environment(\.popover) var popover
@Environment(\.dismissModal) var dismissModal
sheet(view: View): Present a sheet
fullScreenCover(view: View): Present a full-screen cover
popover(view: View): Show a popover
dismissModal(): Dismiss any presented modal
Alerts & Dialogs
@Environment(\.alert) var alert
@Environment(\.confirmationDialog) var confirmationDialog
@Environment(\.openAppSettings) var openAppSettings
alert(title: String, message: String): Show an alert
confirmationDialog(title: String, actions: [Button]): Show a confirmation dialog
openAppSettings(): Directly open the app’s settings
Why?
Clean syntax: This keeps navigation code clean and centralized.
Consistency: Environment values already manage other app-level concerns (color scheme, locale, etc.). Why not navigation too?
Reusability: This approach is easy to adapt across different view hierarchies.
Example
@main
struct App: App {
var body: some Scene {
WindowGroup {
TabView {
NavigationStack {
ProductList()
}
.tabItem { ... }
NavigationStack {
OrderList()
}
.tabItem { ... }
}
}
}
}
struct ProductList: View {
@Environment(\.push) var push
@State var products: [Product] = []
var body: some View {
List(protucts) { product in
Button {
push(destination: ProductDetails(product: product))
}
} label: {
...
}
}
.task { ... }
}
}
struct ProductDetails: View { ... }
I’m so lost on this. I’ve tried Google, ChatGPT, DeepSeek, the documentation. I’ve spent about 7 hours on this specific bug. Not sure what to do next. Does anyone have an idea?
I am trying to build a text editor that shrinks to its content size. The closest I have been able to get has been to add the .scrollDisabled(true) and .fixedSize(horizontal: false, vertical: true) modifiers.
This almost achieves what I need. There are two problems though:
long single line text gets cut off at the end
creating line breaks causes the text editor to grow vertically as expected (uncovering the cut off text in point 1 above). However, when you delete the line breaks, the TextEditor does not shrink again.
I have had a radar open for some time: FB13292506. Hopefully opening a thread here will get more visibility.
And here is some sample code to easily reproduce the issue:
import SwiftUI
struct ContentView: View {
@State var text = "[This is some long text that will be cut off at the end of the text editor]"
var body: some View {
TextEditor(text: $text)
.scrollDisabled(true)
.fixedSize(horizontal: false, vertical: true)
}
}
#Preview {
ContentView()
}
Here is a gif of the behavior: