Hi everyone,
I believe this should be a simple and expected default behavior in a real-world app, but I’m unable to make it work:
I have a View (a screen/page in this case) that calls an endpoint using async/await.
If the endpoint hasn’t finished, but I navigate forward to a DetailView, I want the endpoint to continue fetching data (i.e., inside the @StateObject ViewModel that the View owns). This way, when I go back, the View will have refreshed with the fetched data once it completes.
If the endpoint hasn’t finished and I navigate back to the previous screen, I want it to be canceled, and the @StateObject ViewModel should be deinitialized.
I can achieve 1 and 3 using the .task modifier, since it automatically cancels the asynchronous task when the view disappears:
view
.task { await vm.getData() }
I can achieve 1 and 2 using a structured Task in the View (or in the ViewModel, its the same behavior), for example:
.onFirstAppearOnly {
Task { away vm.getData() }
}
onFirstAppearOnly is a custom modifier that I have for calling onAppear only once in view lifecycle. Just to clarify, I dont think that part is important for the purpose of the example
My question is:
How can I achieve all three behaviors?
My minimum deployment target is iOS 15, and I’m using NavigationView + NavigationLink. However, I have also tried using NavigationStack + NavigationPath and still couldn’t get it to work.
Any help would be much appreciated. Thank you!
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
200 Posts
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
Hello Apple Developer Forum Community,
I’ve got a problem with the display of my SwiftUI View, that is tested on my physical iPhone. It’s shown very small (Picture) and on the Xcode Canvas Simulator it get’s shown right.
What is the problem with my code?
I have a SwiftUI-based universal app which creates a file that it stores in documentsDirectory. On iOS/iPadOS, this file is stored in the application's Documents directory and is accessible via the Files app.
On MacCatalyst, this operation does the same thing — it creates the file and stores it in ~/Library/Containers/<app directory>/Data/Documents. However what I want is for the document to be stored in ~/Documents, so that it is easily accessible to the user.
How can I do that? I'd like it to occur without (for example) having to show a SaveFile panel...
I’m trying to understand how SwiftUI List handles row lifecycle and reuse during scrolling. I have a list with around 60 card views; on initial load, only about 7 rows are created, but after scrolling to the bottom all rows appear to be created, and when scrolling back to the top I again observe multiple updates and apparent re-creation of rows. I confirmed this behavior using Instruments by profiling my app. Even though each row has a stable identifier, the row views still seem to be destroyed and recreated, which doesn’t resemble UIKit’s cell reuse model. I’d like clarity on how List uses identifiers internally, what actually gets reused versus recreated, and how developers should reason about performance and view lifetime in this case.
I'm being faced with an issue when using SwiftUI's WebView on iOS 26. In many websites, the top/bottom content is unaccessible due to being under the app's toolbars. It feels like the WebView doesn't really understand the safe areas where it's being shown, because the content should start right below the navigation bar, and only when the user scrolls down, the content should move under the bar (but it's always reachable if the users scroll back up).
Here's a demo of the issue:
Here's a 'fix' by ensuring that the content of the WebView never leaves its bounds. But as you can see, it feels out of place on iOS 26 (would be fine on previous OS versions if you had a fully opaque toolbar):
Code:
struct ContentView: View {
var body: some View {
NavigationStack {
WebView(url: URL(string: "https://apple.com")).toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Top content covered, unaccessible.") {}
}
}
}
}
}
Does anyone know if there's a way to fix it using some sort of view modifier combination or it's just broken as-is?
When displaying a view with a Button inside a ScrollView using the sheet modifier, if you try to close the sheet by swiping and your finger is touching the Button, the touch is not canceled.
This issue occurs when building with Xcode 16 but does not occur when building with Xcode 15.
Here is screen cast.
https://drive.google.com/file/d/1GaOjggWxvjDY38My4JEl-URyik928iBT/view?usp=sharing
Code
struct ContentView: View {
@State var isModalPresented: Bool = false
var body: some View {
ScrollView {
Button {
debugPrint("Hello")
isModalPresented.toggle()
} label: {
Text("Hello")
.frame(height: 44)
}
Button {
debugPrint("World")
} label: {
Text("World")
.frame(height: 44)
}
Text("Hoge")
.frame(height: 44)
.contentShape(Rectangle())
.onTapGesture {
debugPrint("Hoge")
}
}
.sheet(isPresented: $isModalPresented) {
ContentView()
}
}
}
I was looking through:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_handle_AEs/SAppsHandleAEs.html
And wondered how these are handled for SwiftUI
apps. What would I add or override?
Code example:
//
// ListSafeAreaBarKeyboardTextField.swift
// Exploration
import SwiftUI
import Foundation
struct ListSafeAreaBarKeyboardTextField: View {
@State private var typedText: String = ""
@FocusState private var focusingTextField: Bool
private let items = Array(1...16)
var body: some View {
ScrollViewReader { proxy in
List(items, id: \.self) { number in
Text("Item \(number)")
.id(number)
}
.onAppear {
if let lastItem = items.last {
proxy.scrollTo(lastItem, anchor: .bottom)
}
}
.onChange(of: focusingTextField) { oldValue, newValue in
// This simply won't work
// ~ 12th - 16th item will still get covered by keyboard
if newValue == true {
// Delay to allow keyboard animation to complete
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
if let lastItem = items.last {
withAnimation {
proxy.scrollTo(lastItem, anchor: .top)
}
}
}
}
}
}
.scrollDismissesKeyboard(.interactively)
.safeAreaBar(edge: .bottom) {
TextField("Type here", text: $typedText, axis: .vertical)
.focused($focusingTextField)
// Design
.padding(.horizontal, 16)
.padding(.vertical, 10)
.glassEffect()
// Paddings
.padding(.horizontal, 24)
.padding(.vertical, 12)
}
}
}
How do I set a custom icon for an app control that appears in Control Shortcuts (swipe down from iOS) ?
Where is the documentation for size and where to put the image, format etc?
Thank you.
Working Code (sfsymbol)
import Foundation
import AppIntents
import SwiftUI
import WidgetKit
// MARK: - Open App Control
@available(iOS 18.0, *)
struct OpenAppControl: ControlWidget {
let kind: String = "OpenAppControl"
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: kind, content: {
ControlWidgetButton(action: OpenAppIntent()) {
Label("Open The App", systemImage: "clock.fill")
}
}
})
.displayName("Open The App") // This appears in the shortcuts view
}
}
Sample Image
These apps use their own image. How can I use my own image?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
SwiftUI
WidgetKit
App Intents
Hello,
I am experiencing a layout glitch when using the new .navigationTransition(.zoom) in SwiftUI on iOS 18+. While the primary content transitions smoothly, the Navigation Bar elements (Title and ToolbarItems) of the source view exhibit an unwanted horizontal sliding animation during the transition.
The Problem: As the zoom transition begins, the large inline title and the trailing toolbar buttons do not simply fade out or stay pinned. Instead, they slide to the left of the screen and when destination view is closed they slide back to their place. This creates a "janky" visual effect where the navigation bar appears to collapse or shift its coordinate space while the destination view is expanding.
Problem video link:-
I’m seeing unexpected scroll behavior when embedding a LazyVStack with dynamically sized views inside a ScrollView.
Everything works fine when the item height is fixed (e.g. colored squares), but when I switch to text views with variable height, the scroll position jumps and glitches—especially when the keyboard appears or disappears. This only happens on iOS 26, it works fine on iOS 18.
Working version
struct Model: Identifiable {
let id = UUID()
}
struct ModernScrollView: View {
@State private var models: [Model] = []
@State private var scrollPositionID: String?
@State private var text: String = ""
@FocusState private var isFocused
// MARK: - View
var body: some View {
scrollView
.safeAreaInset(edge: .bottom) { controls }
.task { reset() }
}
// MARK: - Subviews
private var scrollView: some View {
ScrollView {
LazyVStack {
ForEach(models) { model in
SquareView(color: Color(from: model.id))
.id(model.id.uuidString)
}
}
.scrollTargetLayout()
}
.scrollPosition(id: $scrollPositionID)
.scrollDismissesKeyboard(.interactively)
.defaultScrollAnchor(.bottom)
.onTapGesture {
isFocused = false
}
}
private var controls: some View {
VStack {
HStack {
Button("Add to top") {
models.insert(contentsOf: makeModels(3), at: 0)
}
Button("Add to bottom") {
models.append(contentsOf: makeModels(3))
}
Button("Reset") {
reset()
}
}
HStack {
Button {
scrollPositionID = models.first?.id.uuidString
} label: {
Image(systemName: "arrow.up")
}
Button {
scrollPositionID = models.last?.id.uuidString
} label: {
Image(systemName: "arrow.down")
}
}
TextField("Input", text: $text)
.padding()
.background(.ultraThinMaterial, in: .capsule)
.focused($isFocused)
.padding(.horizontal)
}
.padding(.vertical)
.buttonStyle(.bordered)
.background(.regularMaterial)
}
// MARK: - Private
private func makeModels(_ count: Int) -> [Model] {
(0..<count).map { _ in Model() }
}
private func reset() {
models = makeModels(3)
}
}
// MARK: - Color+UUID
private extension Color {
init(from uuid: UUID) {
let hash = uuid.uuidString.hashValue
let r = Double((hash & 0xFF0000) >> 16) / 255.0
let g = Double((hash & 0x00FF00) >> 8) / 255.0
let b = Double(hash & 0x0000FF) / 255.0
self.init(red: abs(r), green: abs(g), blue: abs(b))
}
}
Not working version
When I replace the square view with a text view that generates random multiline text:
struct Model: Identifiable {
let id = UUID()
let text = generateRandomText(range: 1...5)
// MARK: - Utils
private static func generateRandomText(range: ClosedRange<Int>) -> String {
var result = ""
for _ in 0..<Int.random(in: range) {
if let sentence = sentences.randomElement() {
result += sentence
}
}
return result.trimmingCharacters(in: .whitespaces)
}
private static let sentences = [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
]
}
and use it like this:
ForEach(models) { model in
Text(model.text)
.padding()
.multilineTextAlignment(.leading)
.background(Color(from: model.id))
.id(model.id.uuidString)
}
Then on iOS 26, opening the keyboard makes the scroll position jump unpredictably.
It is more visible if you play with the app, but I could not upload a video here.
Environment
Xcode 26.0.1 - Simulators and devices on iOS 26.0 - 18.0
Questions
Is there any known change in ScrollView / scrollPosition(id:) behavior on iOS 26 related to dynamic height content?
Am I missing something in the layout setup that makes this layout unstable with variable-height cells?
Is there a workaround or recommended approach for keeping scroll position stable when keyboard appears?
I have found that following code runs without issue from Xcode, either in Debug or Release mode, yet crashes when running from the binary produced by archiving - i.e. what will be sent to the app store.
import SwiftUI
import AVKit
@main
struct tcApp: App {
var body: some Scene {
WindowGroup {
VideoPlayer(player: nil)
}
}
}
This is the most stripped down code that shows the issue. One can try and point the VideoPlayer at a file and the same issue will occur.
I've attached the crash log:
Crash log
Please note that this was seen with Xcode 26.2 and MacOS 26.2.
I am creating a macOs SwiftUI document based app, and I am struggling with the Window sizes and placements. Right now by default, a normal window has the minimize and full screen options which makes the whole window into full screen mode.
However, I don't want to do this for my app. I want to only allow to fill the available width and height, i.e. exclude the status bar and doc when the user press the fill window mode, and also restrict to resize the window beyond a certain point ( which ideally to me is 1200 x 700 because I am developing on macbook air 13.3-inch in which it looks ideal, but resizing it below that makes the entire content inside messed up ).
I want something like this below instead of the default full screen green
When the user presses the button, it should position centered with perfect aspect ratio from my content ( or the one I want like 1200 x 700 ) and can be able to click again to fill the available width and height excluding the status bar and docs.
Here is my entire @main code :-
@main
struct PhiaApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
DocumentGroup(newDocument: PhiaProjectDocument()) { file in
ContentView(
document: file.$document,
rootURL: file.fileURL
)
.configureEditorWindow(disableCapture: true)
.background(AppColors.background)
.preferredColorScheme(.dark)
}
.windowStyle(.hiddenTitleBar)
.windowToolbarStyle(.unified)
.defaultLaunchBehavior(.suppressed)
Settings {
SettingsView()
}
}
}
struct WindowAccessor: NSViewRepresentable {
var callback: (NSWindow?) -> Void
func makeNSView(context: Context) -> NSView {
let view = NSView()
DispatchQueue.main.async { [weak view] in
callback(view?.window)
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) { }
}
extension View {
func configureEditorWindow(disableCapture: Bool = true) -> some View {
self.background(
WindowAccessor { window in
guard let window else { return }
if let screen = window.screen ?? NSScreen.main {
let visible = screen.visibleFrame
window.setFrame(visible, display: true)
window.minSize = visible.size
}
window.isMovable = true
window.isMovableByWindowBackground = false
window.sharingType = disableCapture ? .captureBlocked : .captureAllowed
}
)
}
}
This is a basic setup I did for now, this automatically fills the available width and height on launch, but user can resize and can go beyond my desired min width and height which makes the entire content inside messy.
As I said, I want a native way of doing this, respect the content aspect ratio, don't allow to enter full screen mode, only be able to fill the available width and height excluding the status bar and doc, also don't allow to resize below my desired width and height.
Instruments is crashing when the swiftui instrument is stopped (the session is finished) and the transfer begins from device to device:
Crashed Thread: 11 Dispatch queue: com.apple.swiftuitracingsupport.reading
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [1633]
I've tried removing derived data, reinstalling xcode, updating xcode (I originally thought this might be the issue -- I needed to update to 26.2 from the 26 RC -- the update didn't fix crash or change the crash report), and restarting both devices.
I'm running Instruments/Xcode 26.2 on a MacBook Pro 15" (2018) running Mac OS 15.7.2 (24G325) with an iPhone 16 Pro Max running 26.2.
Hoping someone else might have seen this or could help me troubleshoot. I find the swiftui instrument be helpful and like to use it :) I can post a complete crash report as well.
When tap the Button quickly in List, the ButtonStyleConfiguration’s isPressed property don't change properly, always false. When using Button in ScrollView, the same error doesn't exist.
My app uses SwiftUI Map and draws Markers, MapPolyline and MapPolygons over it. These all work on actual devices. On the iOS 26.0.1 Simulator running on macOS 26.0.1 Polylines and Polygons do now show.
Do others see the same thing?
Hello,
I am currently in the process of gradually adding support for LiquidGlass to my app. The transition is taking place incrementally, i.e., new screens and minor features are gradually being adapted to the new design and already deployed.
Currently, the old design is still active via the feature flag UIDesignRequiresCompatibility, as the existing UI should remain locked for the public app store version until the transition is complete.
My challenge is as follows:
I would like to work with the new LiquidGlass design during development without having to manually change the UIDesignRequiresCompatibility flag with each deployment.
Ideally, I am looking for a solution where:
• the new design is only activated for me (e.g., specific account or specific devices)
• the old design remains active for all other users
• the App Store version can be delivered unchanged
So my question is:
Is it possible to control UIDesignRequiresCompatibility via remote config or server-side logic in order to activate the new design specifically for certain users or devices?
I have observed similar behavior on WhatsApp—two devices with the same app version, but only one shows the new design. This suggests server-side or remote config-based control.
Do you have any experience or recommendations on how to implement something like this cleanly?
Kind regards
Heinz
I posted https://developer.apple.com/forums/thread/809481 yesterday about an issue I discovered with pushWindow in visionOS 26.2 RC, but today I discovered a second problem with pushWindow.
If window A calls pushWindow to present window B, and the user pins window B to a wall, the following unexpected behaviors are observed:
Window B spontaneously disappears.
If the user re-launches the (still running) app from the visionOS home view, both window A and window B appear simultaneously. I assume only window B should be visible at this point, since window A pushed window B.
If the user closes window B, it's now impossible to present window B again. Calls to pushWindow appear to be ignored.
If the user force-quits the app and relaunches it, and pushWindow is called again, window B appears, but window A remains visible.
I also noticed this surprising behavior:
This broken state of pushWindow behavior now affects all other apps on the system that may call pushWindow in the future, not just the app whose pushed window was pinned above.
A workaround is to reboot the device, and then the system will behave as expected until the next time the user pins a pushed window.
I recently added pushWindow to my app, and I discovered that in visionOS 26.2 RC (23N301), pushWindow followed by dismissWindow no longer works as expected.
Specifically, if the user moves the pushed window, then when the pushed window is later dismissed, the parent window's position isn't aligned with the pushed window's new position. Its original position is restored instead.
Curiously, the bug only happens when an app is launched from the visionOS home view, and not when an app is launched from Xcode. It also doesn't happen in the visionOS 26.2 simulator.
Another interesting detail is that while the parent window is hidden, if the user long-presses the Digital Crown and then dismisses the pushed window, the parent window's position seems to be immune from the Digital Crown scene reorientation. It's restored to its original real world position.
Demo video: https://youtu.be/zR3t2ON3Wz0
I've submitted feedback as FB21287011 with a sample app and detailed repro steps.
Has anyone else encountered this issue already and figured out a workaround? It would be nice if I could get pushWindow to work correctly in my app.
Thanks everybody! 😀