I'm building a SwiftUI app for iPad using a NavigationSplitView as the navigation root. Below is a simplified version of the app's navigation. There are a Home Page and a Settings Page, each with its own NavigationStack. The page that appears in the detail column depends on the sidebar's selection value. The issue I'm facing is that when I navigate deeply into the Home Page's NavigationStack (e.g., to a Home Page Child view), switch to the Settings Page, and then switch back to the Home Page, the Home Page's navigation path has been reset to [] and the previous state is lost. The same issue occurs if I navigate deeply into the Settings Page (e.g., to a Settings Page Child view), switch to the Home Page, and then return to the Settings Page: the navigation state for the Settings Page is lost, and it reverts to the root of the NavigationStack. Why is this happening and how can I fix it so that switching pages in the sidebar doesn't reset the NavigationStack of each individual page in the detail column? Thank you.
struct ContentView: View {
@State var selection: String?
@State var firstPath = [String]()
@State var secondPath = [String]()
var body: some View {
NavigationSplitView {
List(selection: $selection) {
Text("Home")
.tag("home")
Text("Settings")
.tag("settings")
}
} detail: {
if selection == "home" {
HomePage(path: $firstPath)
} else {
SettingsPage(path: $secondPath)
}
}
}
}
struct HomePage: View {
@Binding var path: [String]
var body: some View {
NavigationStack(path: $path) {
NavigationLink("Home Page", value: "Home")
.navigationDestination(for: String.self) { _ in
Text("Home Page Child")
}
}
}
}
struct SettingsPage: View {
@Binding var path: [String]
var body: some View {
NavigationStack(path: $path) {
NavigationLink("Settings Page", value: "Settings")
.navigationDestination(for: String.self) { _ in
Text("Settings Page Child")
}
}
}
}
#Preview {
ContentView()
}
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 am trying to get integer input by using textfield. However, I noticed that if I changed the binding variable as optional with an initial value of null, the textfield would not work. I would like to keep it as null initially because I want the placeholder to show text before the input, and if the int variable starts with any valid value, the text would not be shown. Is there a way to fix things here?
struct TextFieldNumberInputView: View {
@Binding var intVariable: Int?
@State var isEditing: Bool = false
@State var placeholderText: String
@State var number: Int = 0
var body: some View {
VStack(alignment: .leading, spacing: 2){
TextField(placeholderText, value: $number, formatter: NumberFormatter()){
}
.textFieldStyle(InputTextFieldStyle())
.keyboardType(.numberPad)
.onReceive(Just(number)) {_ in
print("number pad being editing")
if isEditing == false && intVariable != nil {
isEditing = true
print("number is being edited")
} else if isEditing == true && intVariable != nil{
isEditing = false
}
}
Text(placeholderText)
.font(.caption2)
.foregroundColor(isEditing ? Color(.systemGray3):Color.clear)
.padding(.horizontal)
.padding(.horizontal, 12)
}.onTapGesture {
print("number pad being tapped, intVariable \(intVariable), \(number)")
if number != nil {
print("checking number")
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to:nil, from:nil, for:nil)
}
}
}
}
Anytime I have 1 item, then add another, the app crashes with the following error:
Swift/IntegerTypes.swift:8835: Fatal error: Double value cannot be converted to Int because it is either infinite or NaN
I'm not working with Int values though, so I'm not sure why this is happening. It's also not point me towards any specific line. I've printed out all of the values being used for the chart and none of them are showing as infinite or NaN.
The data being used is created in a View.
@State private var pieChartData: [PieChartDataPoint] = []
Then in the onAppear and onChange its gets loaded using the following function:
func getPieChartDataPoints() -> [PieChartDataPoint] {
self.map({ PieChartDataPoint(label: $0.name, value: $0.monthlyAmount()) })
}
That's an extension on a SwiftData model type I have called Recurring.
@Model
final class Recurring {
var id = UUID()
enum Kind: String, CaseIterable, Codable {
case income = "Income"
case bill = "Bill"
func plural() -> String {
switch self {
case .income:
"Income"
case .bill:
"Bills"
}
}
}
enum Frequency: String, CaseIterable, Codable, Identifiable {
var id: Frequency { self }
case weekly = "Weekly"
case biweekly = "Biweekly"
case monthly = "Monthly"
case quarterly = "Quarterly"
case annually = "Annually"
}
var name: String = ""
var kind: Kind = Kind.income
var frequency: Frequency = Frequency.biweekly
var amount: Double = 0
init(name: String, kind: Kind, frequency: Frequency, amount: Double) {
self.name = name
self.kind = kind
self.frequency = frequency
self.amount = amount
}
func amount(from cycle: Cycle) -> Double {
switch cycle {
case .weekly:
monthlyAmount() * 12 / 52
case .biweekly:
monthlyAmount() * 12 / 26
case .monthly:
monthlyAmount()
}
}
func monthlyAmount() -> Double {
switch frequency {
case .weekly:
amount * 52 / 12
case .biweekly:
amount * 26 / 12
case .monthly:
amount
case .quarterly:
amount * 4 / 12
case .annually:
amount / 12
}
}
}
Here is the DataPoint structure.
struct PieChartDataPoint: Identifiable, Equatable {
var id = UUID()
var label: String
var value: Double
}
Finally here is the chart.
Chart(sorted, content: { dataPoint in
SectorMark(
angle: .value(dataPoint.label, getValue(from: dataPoint)),
innerRadius: 50,
angularInset: 5
)
.foregroundStyle(by: .value("Label", dataPoint.label))
.cornerRadius(10)
.opacity(getSectorMarkOpacity(for: dataPoint))
})
.scaledToFill()
.chartLegend(.hidden)
.chartAngleSelection(value: $chartSelection)
.onChange(of: chartSelection, checkSelection)
For testing purposes, I have removed all of the modifiers and only had a simple SectorMark in the Chart, however, that was still crashing.
Does anyone know why this is happening?
Hello !
I manage to displays tips on tvOS no issue.
However when I want to add actions, they are not visible. Is there something specific to do here ?
I just provided the actions attributes to my tips.
The documentation does not say anything more.
Thanks!
According to the UtilityWindow documentation:
• They receive FocusedValues from the focused main scene in an application, similar to commands in the main menu, which can be used to display information on the active content as the user focuses on different scenes.
This makes me think that any UtilityWindow, even across Scenes, should always receive @FocusedValues from the currently focused window of any scene.
However, the following code doesn't quite work:
@Observable class Info: Identifiable {
let id = UUID()
}
struct ExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView() // Inside, it uses .focusedSceneValue(info)
}
UtilityWindow("Test") {
UtilityWindowContent()
}
}
}
struct UtilityWindowContent: View {
@FocusedValue(Info.self) var info
var body: some View {
Text(info?.id ?? "<nil>") // This always shows "<nil>"
}
}
Here's some annotated screenshots of what's happening in a project:
Menu bar commands do work with the same setup:
As a workaround, attempting to use @FocusedValue in the App struct works, but as a result, the value appears to instantiate multiple times in the background, and they re-instantiate with every focus change.
The @FocusedValue variable gets the correct instance, but it's needlessly initializing others in the background.
This is on macOS 26.0 Tahoe Beta 8 (25A5349a).
Summary
In a SwiftUI drag-and-drop flow, the only robust way I’ve found to detect cancellation (user drops outside any destination) is to rely on the NSItemProvider created in .onDrag and run cleanup when it’s deallocated, via a custom onEnded callback tied to its lifecycle.
On iOS 26, the provider appears to be deallocated immediately after .onDrag returns (unless I keep a strong reference), so a deinit/onEnded-based cancel hook fires right away and no longer reflects the true end of the drag session.
I’d like to know:
1. Is there a supported, reliable way to detect when a drag ends outside any drop target so I can cancel and restore the source row?
2. Is the iOS 26 NSItemProvider deallocation timing a bug/regression or intended behavior?
Minimal SwiftUI Repro
This example shows:
• creating a custom NSItemProvider subclass with an onEnded closure
• retaining it to avoid immediate dealloc (behavior change on iOS 26)
• using performDrop to mark the drag as finished
import SwiftUI
import UniformTypeIdentifiers
final class DragProvider: NSItemProvider {
var onEnded: (() -> Void)?
deinit {
// Historically: called when the system drag session ended (drop or cancel).
// On iOS 26: can fire immediately after .onDrag returns unless the provider is retained.
onEnded?()
}
}
struct ContentView: View {
struct Item: Identifiable, Equatable { let id = UUID(); let title: String }
@State private var pool: [Item] = (1...4).map { .init(title: "Option \($0)") }
@State private var picked: [Item] = []
@State private var dragged: Item?
@State private var dropFinished: Bool = true
@State private var activeProvider: DragProvider? // Retain to avoid immediate dealloc
private let dragType: UTType = .plainText
var body: some View {
HStack(spacing: 24) {
// Destination list (accepts drops)
VStack(alignment: .leading, spacing: 8) {
Text("Picked").bold()
VStack(spacing: 8) {
ForEach(picked) { item in
row(item)
}
}
.padding()
.background(RoundedRectangle(cornerRadius: 8).strokeBorder(.quaternary))
.onDrop(of: [dragType], delegate: Dropper(
picked: $picked,
pool: $pool,
dragged: $dragged,
dropFinished: $dropFinished,
activeProvider: $activeProvider
))
}
.frame(maxWidth: .infinity, alignment: .topLeading)
// Source list (draggable)
VStack(alignment: .leading, spacing: 8) {
Text("Pool").bold()
VStack(spacing: 8) {
ForEach(pool) { item in
row(item)
.onDrag {
startDrag(item)
return makeProvider(for: item)
} preview: {
row(item).opacity(0.9).frame(width: 200, height: 44)
}
.overlay(
RoundedRectangle(cornerRadius: 8)
.fill(item == dragged ? Color(.systemBackground) : .clear) // keep space
)
}
}
.padding()
.background(RoundedRectangle(cornerRadius: 8).strokeBorder(.quaternary))
}
.frame(maxWidth: .infinity, alignment: .topLeading)
}
.padding()
}
private func row(_ item: Item) -> some View {
RoundedRectangle(cornerRadius: 8)
.strokeBorder(.secondary)
.frame(height: 44)
.overlay(
HStack { Text(item.title); Spacer(); Image(systemName: "line.3.horizontal") }
.padding(.horizontal, 12)
)
}
// MARK: Drag setup
private func startDrag(_ item: Item) {
dragged = item
dropFinished = false
}
private func makeProvider(for item: Item) -> NSItemProvider {
let provider = DragProvider(object: item.id.uuidString as NSString)
// NOTE: If we DO NOT retain this provider on iOS 26,
// its deinit can run immediately (onEnded fires too early).
activeProvider = provider
provider.onEnded = { [weak self] in
// Intended: run when system drag session ends (drop or cancel).
// Observed on iOS 26: may run too early unless retained;
// if retained, we lose a reliable "session ended" signal here.
DispatchQueue.main.async {
guard let self else { return }
if let d = self.dragged, self.dropFinished == false {
// Treat as cancel: restore the source item
if !self.pool.contains(d) { self.pool.append(d) }
self.picked.removeAll { $0 == d }
}
self.dragged = nil
self.dropFinished = true
self.activeProvider = nil
}
}
return provider
}
// MARK: DropDelegate
private struct Dropper: DropDelegate {
@Binding var picked: [Item]
@Binding var pool: [Item]
@Binding var dragged: Item?
@Binding var dropFinished: Bool
@Binding var activeProvider: DragProvider?
func validateDrop(info: DropInfo) -> Bool { dragged != nil }
func performDrop(info: DropInfo) -> Bool {
guard let item = dragged else { return false }
if let idx = pool.firstIndex(of: item) { pool.remove(at: idx) }
picked.append(item)
// Mark drag as finished so provider.onEnded won’t treat it as cancel
dropFinished = true
dragged = nil
activeProvider = nil
return true
}
}
}
Questions
Is there a documented, source-side callback (or best practice) to know the drag session ended without any performDrop so we can cancel and restore the item?
Has the NSItemProvider deallocation timing (for the object returned from .onDrag) changed intentionally on iOS 26? If so, what’s the recommended replacement signal?
Is there a SwiftUI-native event to observe the end of a drag session that doesn’t depend on the provider’s lifecycle?
Hi, i'm using the PasteButton component to paste content from clipboard. On the docs it says that the PasteButton will handle internally permissions and will not present the prompt. But in my case seems to be not true.
I removed all the occurrencies of
UIPasteboard.general.string
since i read that this will cause the prompt to appear. Also as you can see on the code below i'm not doing fancy or weird things, even with the base component this behaviour is still there.
PasteButton(payloadType: String.self) { strings in
if let first = strings.first {
print("clipboard text: \(first)")
}
}
I can see other apps using this paste button without asking for permissions every time, but i cannot see any issue in my code.
Hello,
I am experiencing a crash in a SwiftUI app.
It happens when I place multiple views inside a ScrollView.
The crash occurs only on a physical device (it does not reproduce in the Simulator).
It happens during runtime, seemingly while SwiftUI is updating or laying out the view hierarchy.
I have not been able to determine the exact cause.
I am attaching a text file with the entire backtrace from LLDB.
swiftui_crash_backtrace
Is this a known SwiftUI issue?
Any recommendations on how to further investigate or work around it?
Any help or suggestions would be appreciated.
Xcode 16.3 / iOS 18.6.2
Thank you!
Hello,
I’ve encountered what seems to be a bug with the keyboard dismissal animation on iOS 26.0 Beta (25A5349a), Xcode Version 26.0 beta 5 (17A5295f).
When dismissing the keyboard from a SwiftUI TextField using @FocusState, the keyboard does not animate downward as expected. Instead, it instantly disappears, which feels jarring and inconsistent with system behavior.
I am attaching a short video demonstrating the issue. Below is the minimal reproducible code sample:
//
// ContentView.swift
// TestingKeyboardDismissal
//
// Created by Sasha Morozov on 27/08/25.
//
import SwiftUI
struct ContentView: View {
@State private var text: String = ""
@FocusState private var isFocused: Bool
var body: some View {
ZStack {
Color.clear.ignoresSafeArea()
VStack(spacing: 20) {
TextField("Enter text here...", text: $text)
.textFieldStyle(.roundedBorder)
.focused($isFocused)
.padding(.horizontal)
HStack {
Button("Focus") { isFocused = true }
.buttonStyle(.borderedProminent)
Button("Unfocus") { isFocused = false }
.buttonStyle(.bordered)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.padding()
}
.ignoresSafeArea(.keyboard, edges: .bottom)
}
}
#Preview {
ContentView()
}
Steps to reproduce:
Run** the app on iOS 26.0 beta 5 (17A5295f).
Tap Focus → keyboard appears as expected.
Tap Unfocus → keyboard disappears instantly without the usual slide-down animation.
Expected result:
Keyboard should animate smoothly downwards when dismissed.
Actual result:
Keyboard instantly vanishes without animation.
p.s. we should be really able to upload videos here for demostration
When building with the iOS 26 SDK (currently beta 4), the navigation title is often illegible when rendering a Map view.
For example, note how the title "Choose Location" is obscured by the map's text ("South America") in the screenshot below:
This screenshot is the result of the following view code:
import MapKit
import SwiftUI
struct Demo: View {
var body: some View {
NavigationStack {
Map()
.navigationTitle(Text("Choose Location"))
.navigationBarTitleDisplayMode(.inline)
}
}
}
I tried using the scrollEdgeEffectStyle(_:for:) modifier to apply a scroll edge effect to the top of the screen, in hopes of making the title legible, but that doesn't seem to have any effect. Specifically, the following code seems to produce the exact same result shown in the screenshot above.
import MapKit
import SwiftUI
struct Demo: View {
var body: some View {
NavigationStack {
Map()
.scrollEdgeEffectStyle(.hard, for: .top) // ⬅️ no apparent effect
.navigationTitle(Text("Choose Location"))
.navigationBarTitleDisplayMode(.inline)
}
}
}
Is there a recommended way to resolve this issue so that the navigation title is always readable?
Hello!
I have experienced a weird bug in iOS 26 Beta (8) and previous beta versions. The safe area inset is not correctly aligned with the keyboard toolbar on real devices and simulators.
When you focus a new textfield the bottom safe area is correctly placed aligned the keyboard toolbar.
On real devices the safe area inset view is covered slightly by the keyboard toolbar, which is even worse than on the simulator.
Here's a clip from a simulator:
Here's the code that reproduced the bug I experienced in our app.
#Preview {
NavigationStack {
ScrollView {
TextField("", text: .constant(""))
.padding()
.background(Color.secondary)
TextField("", text: .constant(""))
.padding()
.background(Color.green)
}
.padding()
.safeAreaInset(edge: .bottom, content: {
Color.red
.frame(maxWidth: .infinity)
.frame(height: 40)
})
.toolbar {
ToolbarItem(placement: .keyboard) {
Button {} label: {
Text("test")
}
}
}
}
}
NavigationLinks do not display correctly in tvOS 26. When using a Button, the correct behavior of vertically placing an Image or AsyncImage above one or two Text fields occurs. However, when using NavigationLink the image and text(s) are laid out horizontally. Attempting to fix this using a VStack prevents the text from sliding down as the NavigationLink receives focus. Using the hoverEffect modifier does not help.
Using a Button (correct behavior):
Using a NavigationLink without VStack:
Using a NavigationLink with VStack:
I have a custom list and I want to make the names in the list editable through double tap. I know how to solve this hacky ways.
But are there no solid way to achieve this? like having .disabled without graying it out?
Topic:
UI Frameworks
SubTopic:
SwiftUI
When building with iOS 26 SDK beta 5 (23A5308f), onTapGesture is no longer being triggered on Map views. This appears to be a regression in beta 5 specifically, as this issue was not present in beta 4.
How to reproduce
Code
The following code demonstrates the issue, as seen in the videos below.
import MapKit
import SwiftUI
struct ContentView: View {
@State private var location = CGPoint.zero
var body: some View {
Map()
.onTapGesture { location in
self.location = location
}
.safeAreaInset(edge: .bottom) {
VStack(alignment: .center) {
Text("iOS \(UIDevice.current.systemVersion)")
.font(.largeTitle)
Text("Tapped Location")
Text("\(location.x), \(location.y)")
}
.frame(maxWidth: .infinity, alignment: .center)
.background(.background)
}
}
}
Demo
The gifs below show the behavior in iOS 18.5 (in which the tap gestures are recognized and tapped coordinate is displayed in the safe area inset) and iOS 26 beta 5 (in which the tap gestures have no effect):
iOS 18
iOS 26
Next steps?
Is there a recommended workaround for this issue?
On iPhone, I would like to have a more button at the top right of the navigation bar, a search field in the bottom toolbar, and a plus button to the right of the search field. I've achieved this via the code below.
But on iPad they should be in the navigation bar at the trailing edge from left to right: plus, more, search field. Just like the Shortcuts app, if there's not enough horizontal space, the search field should collapse into a button, and with even smaller space the search bar should become full-width under the navigation bar.
Right now on iPad the search bar is full width under the navigation bar, more at top right, plus at bottom middle, no matter how big the window is.
How can I achieve that? Any way to specify them for the system to more automatically do the right thing, or would I need to check specifically for iPhone vs iPad UIDevice to change the code?
struct ContentView: View {
@State private var searchText = ""
var body: some View {
NavigationStack {
VStack {
Text("Hello, world!")
}
.navigationTitle("Test App")
.searchable(text: $searchText)
.toolbar {
ToolbarItem {
Menu {
//...
} label: {
Label("More", systemImage: "ellipsis")
}
}
DefaultToolbarItem(kind: .search, placement: .bottomBar)
ToolbarSpacer(.fixed, placement: .bottomBar)
ToolbarItem(placement: .bottomBar) {
Button {
print("Add tapped")
} label: {
Label("Add", systemImage: "plus")
}
}
}
}
}
}
Hi,
In the WWDC25 session Elevate an app with Swift concurrency (timestamps: 8:04 and later), the StickerViewModel is shown annotated with @Observable but not @MainActor. The narration mentions that updates happen on the main thread, but that guarantee is left implicit in the calling code.
In Swift 6, though, one of the major benefits is stronger compiler enforcement against data races and isolation rules. If a view model were also annotated with @MainActor, then the compiler could enforce that observable state is only updated on the main actor, preventing accidental background mutations or updates that can cause data races between nonisolated and main actor-isolated uses.
Since @Observable already signals that state changes are intended to be observed (and in practice, usually by views), it seems natural that such types should also be main-actor isolated. Otherwise, we’re left with an implicit expectation that updates will always come from the main thread, but without the compiler’s help in enforcing that rule.
This also ties into the concept of local reasoning that was emphasized in other Swift 6 talks (e.g. Beyond the basics of structured concurrency). With @MainActor, I can look at a view model and immediately know that all of its state is main-actor isolated. With only @Observable, that guarantee is left out, which feels like it weakens the clarity that Swift 6 is trying to promote.
Would it be considered a best practice in Swift 6 to use both @Observable and @MainActor for UI-facing view models? Or is the intention that SwiftUI developers should rely on calling context to ensure main-thread updates, even if that means the compiler cannot enforce isolation?
Thanks!
I really enjoyed using SwiftData for persistence until I found out that the CloudKit integration ensures changes are only eventually consistent, and that changes can propagate to other devices after as long as minutes, making it useless for any feature that involves handoff between devices. Devastating news but I guess it’s on me for nrtfm. I may try my hand at a custom model context DataStore integrating Powersync, but that’s a whole trip and before I embark on it I was wondering if anyone had suggestions for resolving this problem in a simple and elegant manager that allows me to keep as much of the machinery within Apple’s ecosystem as possible, while ensure reliable “live” updates to SwiftData stores on all eligible devices.
Hi guys!
I wanted to study this new ManipulationComponent(), but I keep getting a warning that I don’t understand, even in a very simple scenario.
i don't have any collisions just binding the Manipulation
the warning message is :
** Entity returned from EntityWrapper.makeEntity(context:) was already parented to another entity. This is not supported and may lead to unexpected behavior. SwiftUI adds entities to internally-managed entity hierarchies.**
RealityView { content, attachments in
if let loadedModel = try? await Entity(named: "cloud_glb", in: realityKitContentBundle) {
content.add(loadedModel)
loadedModel.components.set(ManipulationComponent())
}
Thanks !
I've been exploring the resources from WWDC25 Session 280: "Code-along: Cook up a rich text experience in SwiftUI with AttributedString" and the SwiftUI documentation on "Building rich SwiftUI text experiences." After spending some time experimenting and trying to implement these features with these APIs on iOS26 , I’ve run into a specific question.
Is there a way to programmatically trigger the Format Sheet directly—for example, from a custom button—rather than requiring the user to go through the multi-step process of selecting text, opening the context menu, tapping "Format," and then selecting "More"?
I’d like to provide a more streamlined editing experience in my app. Any guidance would be greatly appreciated!
In my SwiftUI iOS app, I need to detect which key (and modifier flags – Command, Option, Shift, Control) a user presses, but I don't want to pre-register them using .keyboardShortcut(_:modifiers:).
My use case is that keyboard shortcuts are user-configurable, so I need to capture the actual key + modifier combination dynamically at runtime and perform the appropriate action based on the user’s settings.
Questions:
What is the recommended way to detect arbitrary key + modifier combinations in SwiftUI on iOS?
Is there a SwiftUI-native solution for this, or should I rely on UIPressesEvent and wrap it with UIViewControllerRepresentable?
If UIKit bridging is necessary, what is the cleanest pattern for integrating this with SwiftUI views (e.g., Buttons)?
Any official guidance or best practices would be greatly appreciated!