I have an iOS app that uses RealityView to display some models and interact with them, and the app uses regular iOS app navigations, then a challenge I'm facing is how to maintain multiple RealityView on multiplescreens.
For example Screen A has a RealityView, and then I navigate to Screen B (also has a RealityView) using stack based navigation, when I do so I got a crash
-[MTLDebugRenderCommandEncoder validateCommonDrawErrors:]:5970: failed assertion `Draw Errors Validation
Fragment Function(fsRealityPbr): argument envProbeTable[0] from Buffer(7) with offset(0) and length(16) has space for 16 bytes, but argument has a length(864).
Fragment Function(fsRealityPbr): incorrect type of texture (MTLTextureType2D) bound at Texture binding at index 20 (expect MTLTextureTypeCubeArray) for envProbeDiffuseArray[0].
Interestingly this crash only happens when debugging with Xcode, not happens when the app runs on its own.
I'm not sure what I'm doing is anti-pattern or it's some Xcode debugging limitation.
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 an app that syncs with Apple Health events. Every time an event occurs, the app should send a notification.
The problem occurs when the app is backgrounded or force-closed; it can no longer send local notifications, and because these events can occur at any time, scheduled notifications can't be used.
I'm just wondering if anyone's found a creative way around this. I know we can't override system behaviour, I'm just thinking of other alternative solutions for the matter.
Hello everyone! I am trying to wrap a ViewModifier inside a Swift Package that bundles a metal shader file to be used in the modifier. Everything works as expected in the Preview, in the Simulator and on a real device for iOS. It also works in Preview and in the Simulator for tvOS but not on a real AppleTV. I have tried this on a 4th generation Apple TV running tvOS 26.3 using Xcode 26.2.0.
Xcode logs the following: The metallib is processed and exists in the bundle.
Compiler failed to build request
precondition failure: pipeline error: custom_effect-fg2a5cia7fmha4: error: unresolved visible function reference: custom_fn
Reason: visible function not loaded
Compiler failed to build request
precondition failure: pipeline error: custom_effect-fg2a5cia7fmha4: error: unresolved visible function reference: custom_fn
Reason: visible function not loaded
Compiler failed to build request
precondition failure: pipeline error: custom_effect-fg2a5cia7fmha4: error: unresolved visible function reference: custom_fn
Reason: visible function not loaded
Compiler failed to build request
precondition failure: pipeline error: custom_effect-fg2a5cia7fmha4: error: unresolved visible function reference: custom_fn
Reason: visible function not loaded
Compiler failed to build request
precondition failure: pipeline error: custom_effect-fg2a5cia7fmha4: error: unresolved visible function reference: custom_fn
Reason: visible function not loaded
Compiler failed to build request
precondition failure: pipeline error: custom_effect-fg2a5cia7fmha4: error: unresolved visible function reference: custom_fn
Reason: visible function not loaded
Contents of Package.swift:
import PackageDescription
let package = Package(
name: "Test",
platforms: [
.iOS(.v17),
.tvOS(.v17)
],
products: [
.library(
name: "Test",
targets: [
"Test"
]
)
],
targets: [
.target(
name: "Test",
resources: [
.process("Shaders")
]
),
.testTarget(
name: "TestTests",
dependencies: [
"Test"
]
)
]
)
Content of my metal file:
#include <metal_stdlib>
using namespace metal;
[[ stitchable ]] float2 complexWave(float2 position, float time, float2 size, float speed, float strength, float frequency) {
float2 normalizedPosition = position / size;
float moveAmount = time * speed;
position.x += sin((normalizedPosition.x + moveAmount) * frequency) * strength;
position.y += cos((normalizedPosition.y + moveAmount) * frequency) * strength;
return position;
}
And my ViewModifier:
import MetalKit
import SwiftUI
extension ShaderFunction {
static let complexWave: ShaderFunction = {
ShaderFunction(
library: .bundle(.module),
name: "complexWave"
)
}()
}
extension Shader {
static func complexWave(arguments: [Shader.Argument]) -> Shader {
Shader(function: .complexWave, arguments: arguments)
}
}
struct WaveModifier: ViewModifier {
let start: Date = .now
func body(content: Content) -> some View {
TimelineView(.animation) { context in
let delta = context.date.timeIntervalSince(start)
content
.visualEffect { view, proxy in
view.distortionEffect(
.complexWave(
arguments: [
.float(delta),
.float2(proxy.size),
.float(0.5),
.float(8),
.float(10)
]
),
maxSampleOffset: .zero
)
}
}
.onAppear {
let paths = Bundle.module.paths(forResourcesOfType: "metallib", inDirectory: nil)
print(paths)
}
}
}
extension View {
public func wave() -> some View {
modifier(WaveModifier())
}
}
#Preview {
Image(systemName: "cart")
.wave()
}
Any help is appreciated.
I have a SwiftUI app displaying tabbed windows (as NSWindowTab) in a WindowGroup:
import SwiftUI
@main
struct TabTestApp: App {
var body: some Scene {
WindowGroup{
ContentView() // Hasn't any content of relevance to this question.
}.commands{
CommandGroup(after: .newItem) {
Button("New Tab") {
guard let currentWindow = NSApp.keyWindow, let windowController = currentWindow.windowController else { return }
windowController.newWindowForTab(nil)
guard let newWindow = NSApp.keyWindow else { return }
if currentWindow != newWindow {
currentWindow.addTabbedWindow(newWindow, ordered: .above)
}
}.keyboardShortcut(.init("t", modifiers: [.command]))
}
}
}
}
Is there a way to detect the closing of one or multiple tabs, e.g. when the user clicks on the tab bar's "Close Other Tabs" option or pushes CMD + W in order to ask the user whether he or she wants to save changes?
What I've tried to no avail:
Intercept windowWillClose👉Won't be called if a single tab within a window is closed (but only once the last tab of a window is closed).
Handling onDissapear()👉Doesn't work since the closing cannot be cancelled.
Using DocumentGroup 👉Doesn't work since the app in question isn't about documents (i.e., files which are stored externally), but about data that's stored in a database.
Many thanks!
Related threads:
Preserve all tabs of last window on close. (Like Finder)
Detect Close Window vs Close Tab
Hello everyone,
I’m running into an issue where a partial sheet repeatedly presents and dismisses in a loop.
Setup
The main screen is presented using fullScreenCover
From that screen, a button triggers a standard partial-height sheet
The sheet is presented using .sheet(item:)
Expected Behavior
Tapping the button should present the sheet once and allow it to be dismissed normally.
Actual Behavior
After the sheet is triggered, it continuously presents and dismisses.
What I’ve Verified
The bound item is not being reassigned in either the parent or the presented view
There is no .task, .onAppear, or .onChange that sets the item again
The loop appears to happen without any explicit state updates
Additional Context
I encountered a very similar issue when iOS 26.0 was first released
At that time, moving the .sheet modifier to a higher parent level resolved the issue
The problem has now returned on iOS 26.4 beta
I’m currently unable to reproduce this in a minimal sample project, which makes it unclear whether:
this is a framework regression, or
I’m missing a new presentation requirement
Environment
iOS: 26.4 beta
Xcode: 26.4 beta
I’ve attached a screen recording of the behavior.
Has anyone else experienced this with a fullScreenCover → sheet flow on iOS 26.4?
Any guidance or confirmation would be greatly appreciated.
Thank you!
When using .searchable with placement: .toolbarPrincipal inside a NavigationStack, the search field is incorrectly placed at the bottom of the view instead of the principal position where ToolbarPlacement.principal normally resides. This is confirmed by testing: a ToolbarItem with placement: .principal containing Text("Title") gets pushed away when the .searchable modifier is added, yet the search field still appears at the bottom rather than taking over the principal location as documented.
I have an app with fairly typical requirements - I need to insert some data (in my case from the network but could be anything) and I want to do it in the background to keep the UI responsive.
I'm using SwiftData.
I've created a ModelActor that does the importing and using the debugger I can confirm that the data is indeed being inserted.
On the UI side, I'm using @Query and a SwiftUI List to display the data but what I am seeing is that @Query is not updating as the data is being inserted. I have to quit and re-launch the app in order for the data to appear, almost like the context running the UI isn't communicating with the context in the ModelActor.
I've included a barebones sample project. To reproduce the issue, tap the 'Background Insert' button. You'll see logs that show items being inserted but the UI is not showing any data.
I've tested on the just released iOS 18b3 seed (22A5307f).
The sample project is here:
https://hanchor.s3.amazonaws.com/misc/SwiftDataBackgroundV2.zip
I'm building an app that heavily relies on EKEventStore for calendar and reminder integration. The API is simple - and limited.
Change notifications amount to "something changed, you'd better refetch everything you care about." There's no way to know whether the calendar was updated while your app was closed or backgrounded. EKEvents and EKReminders don't trigger SwiftUI view updates, so you end up shunting them into your own observable state and keeping the two in sync.
My app is fairly complex rendering-wise, and I lament being locked into treating EKEventStore as a first-class citizen of my view and data layer. It makes everything clunkier, essentially shuts the door on modern features like undo/redo, and makes integrating with other calendar providers that much harder.
I'm exploring a custom SwiftData DataStore ↔ EKEventStore sync engine, but this is no easy task. There are still many unknowns I'd need to spike out before I can even attempt a proper implementation.
Still, I'm curious - is this something being actively worked on behind the scenes? Will we see a more modern, observable, SwiftUI-native EventKit integration in the future?
A watchOS widget requires you set a container background:
.containerBackground(for: .widget) {
Color.black
}
But I see some .accessoryRectangular widgets, on the Smart Stack, using a glass background. From what I know there is no way to set this using .containerBackground. Does anyone know how to do this?
Thank you
When using the .glassEffect modifier on a button in swiftui combined with the .interactive() modifier, the button continues to show the interactive animation even when it’s covered by another element.
Example:
ZStack {
Button {
print("Button overlayed by ZStack") // Does not trigger, but interactive animation still plays
} label: {
image
}
.glassEffect(.regular.interactive())
Rectangle().fill(.black.opacity(0.7))
}
This occurs with overlays, ZStacks, and even if the overlay is a button.
Example below: EDIT: It seems like rocketsim's gif recording doesnt show the bug for some reason... really strange... Edit 2: reuploaded gif, recorded as mp4 and converted to gif seems to have worked...
Feedback ID: FB22054300
I've attached this sample app to my feedback ticket to help with debugging the issue. It doesn't look like I can share it in this post though.
Good afternoon all,
I have a question about Live Activities, specifically ProgressView. Why are they so hard to customize? You can't even really, consistently make the bar a specific height in points. You can't provide any progress view style to make it richer and more dynamic.
We want to build a progress bar that's built up of 3 components: a track with its value constant on 1.0 (the full progress) with a specific color, another track that's the actual progress from ProgressView(timerInterval:countsDown:), and some way to create a visual gap in between.
The progress bar should also be bigger than the standard size from iOS, but that's also not possible. The corners become really ugly when you use the scaleEffect modifier.
Please, if anyone has any ideas about customizing the ProgressView without me having to send push notifications to manually make sure the bar updates, comment down below.
In SwiftUI, when using NavigationStack with a path binding containing multiple instances of the same (or many with navigationPath()) model type (since model type are class type, this issue might occur on instances of class type too), any NavigationLink in a detail view that leads to a value already present anywhere in the navigation stack (which is in the path binding) will appear incorrectly highlighted upon the view's initial appearance. This bug seems manifests specifically when the links are contained within a List. The highlighting is inconsistent - only the earliest appended value in path has link in each section displays as pressed, while links to other value appear normal.
Below is a simple code to reproduce the bug.
import SwiftUI
import SwiftData
// Simple model
@available(iOS 17, *)
@Model
class Item {
var id = UUID()
var name: String
var relatedItems: [Item]
init(name: String = "", relatedItems: [Item] = []) {
self.name = name
self.relatedItems = relatedItems
}
}
// MARK: - Bug Reproducer
@available(iOS 17, *)
struct BugReproducerView: View {
@State private var path: [Item] = []
let items: [Item]
init() {
let item1 = Item(name: "Item 1", relatedItems: [])
let item2 = Item(name: "Item 2", relatedItems: [item1])
item1.relatedItems = [item2]
self.items = [item1, item2]
}
var body: some View {
NavigationStack(path: $path) {
List(items) { item in
NavigationLink(item.name, value: item)
}
.navigationTitle("Items")
.navigationDestination(for: Item.self) { item in
DetailView(item: item)
}
}
}
}
// MARK: - Detail View with Bug
@available(iOS 17, *)
struct DetailView: View {
let item: Item
var body: some View {
List {
Section("Info") {
Text("Selected: \(item.name)")
}
if !item.relatedItems.isEmpty {
Section("Related") {
ForEach(item.relatedItems) { related in
NavigationLink(related.name, value: related)
}
}
}
}
.navigationTitle(item.name)
}
}
#Preview {
if #available(iOS 17, *) {
BugReproducerView()
} else {
}
}
Hi, everyone. I'm trying my first TimelineView with an explicit schedule, but my attempt – and even the simple example from the documentation – doesn't seem to work as documented. Here's what the documentation says an explicit schedule does:
The timeline view updates its content on exactly the dates that you specify, until it runs out of dates, after which it stops changing.
And it gives this example:
let dates = [
Date(timeIntervalSinceNow: 10), // Update ten seconds from now,
Date(timeIntervalSinceNow: 12), // and a few seconds later.
]
struct MyView: View {
var body: some View {
TimelineView(.explicit(dates)) { context in
Text(context.date.description)
}
}
}
There are stipulations about what the view – which always displays some version of its content body – will do given only past or future dates, but it seems clear we should expect the view in this example to redraw at least once after it appears.
Here's the rest of the discussion from the documentation with my comments after testing what's stated:
If the dates you provide are in the past, the timeline view updates exactly once with the last entry.
That seems true, considering the "update" to be the initial draw.
If you only provide dates in the future, the timeline view renders with the current date until the first date arrives.
Not exactly: it looks the "date" property of the initial render is the (future) date of the first schedule entry, even though it's drawn early. When the first date does arrive, the body closure doesn't seem to be called. Only on the next date, if there is one, is it called again.
If you provide one or more dates in the past and one or more in the future, the view renders the most recent past date, refreshing normally on all subsequent dates.
That also seems correct, except…
… that in every scenario, the final date entry seems to be ignored completely! In other words, unless all date entries are in the past, the Timeline View stops before it runs out of dates. That documented example from the start, which we expect to redraw at least once after it appears? When I test it in a Playground, it appears, but doesn't redraw at all!
So, that's my main point of confusion after experimenting with TimelineView for the first time. I can achieve my own goal by appending an extra entry to my explicit schedule – even appending an entry identical to the previous "final" entry seems to work – but naturally that leaves me unclear about why I need to.
If anyone can tell me what I'm not understanding, I'd be grateful.
FeedBack Id: FB22031397 (Demo proj Attached to Feedback)
Description:
When a TabView using .page tabViewStyle is placed inside a sheet configured with multiple presentationDetents, dragging the sheet handle to resize between detents causes the TabView to re-render all its pages on every frame of the drag gesture. This results in visible content vibration, scroll position jumping, and tab content flashing during the drag. The issue is fully reproducible with the attached minimal demo project.
Steps to Reproduce:
Run the attached TabViewSheetVibrationDemo.swift on any iOS device or simulator
Tap "Open Sheet" on the main screen
Swipe left to any tab
Scroll down inside the tab so content is not at the top
Grab the sheet drag indicator at the top and slowly drag upward or downward to resize between medium and large detent
Observe the tab content while dragging
Expected Results:
The TabView page content should remain completely stable during sheet resize. Scroll positions should be preserved and no re-rendering should occur because the underlying data has not changed. The sheet should resize smoothly while tab content stays still.
Actual Results:
The TabView re-renders all pages on every frame of the drag gesture. This causes:
Visible content vibration and jitter while dragging the sheet handle
Scroll position jumping back toward the top mid-drag
Tab content flashing as pages are recreated
The problem is proportional to drag speed — slower drags show a stuttering effect, faster drags cause a full content flash
Configuration:
All Xcode including beta
iOS 26 (also reproduced on iOS 16, iOS 17 and iOS 18)
Reproducible on both Simulator and real device
Affects iPhone and iPad
I have the following code that renders a one-page PDF:
func render() -> URL {
let renderer = ImageRenderer(content: pdfView())
let url = URL.documentsDirectory.appending(path: "filename.pdf")
renderer.render { size, context in
var document = CGRect(x: 0, y: 0, width: 2550, height: 3300)
guard let pdf = CGContext(url as CFURL, mediaBox: &document, nil) else {
return
}
pdf.beginPDFPage(nil)
context(pdf)
pdf.endPDFPage()
pdf.closePDF()
}
return url
}
func pdfView() -> some View {
Text("View")
}
How can this be modified so that it renders a PDF with more than one page?
My app is a UIKit app with a lot of SwiftUI mixed in. A common scenario is that a UIViewController presents a sheet with a SwiftUI view wrapped in a UIHostingController.
When I present the exact same SwiftUI View it looks different in a SwiftUI sheet compared to when it's wrapped in a UIHostingController and presented from a view controller.
I'm using a hacky workaround in which I loop through all subviews of the hosting controller in viewWillLayoutSubviews and look for a NavigationStackHostingController<SwiftUI.AnyView> to manually set the background color, but it feels like it could brake easily.
Has anyone found a better way to fix this?
Feedback: FB22028838
My visionOS 26.3 app displays a diorama-like scene in a RealityView in a mixed immersive space, about 1 meter square, with view attachments floating above the scene.
Each view attachment fades out after user interaction, by animating the view's opacity.
What I'm observing is that depending on the position of a view attachment relative to the scene and the camera, an unwanted cutout effect is observed (presumably because of draw order issues), as shown in the right column in the screenshots below.
YouTube video link of these sequences: https://youtu.be/oTuo0okKCkc
(19 seconds)
My question:
How does visionOS determine the view attachment draw order relative to the RealityView scene?
If I better understood how the draw order is determined, I could modify my scene to ensure that the view attachments were always drawn after the scene, fixing the unwanted cutout effect.
I've successfully used ModelSortGroupComponent to control the draw order of entities within the RealityView scene, but my understanding is that this approach cannot be used with view attachments.
I've submitted FB22014370 about this issue.
Thank you.
When making an element with .glassEffect(.clear.interactive()) draggable, it stretches as it moves.
It seems like it's meant to stretch as you move your finger away from the element, but it doesn't make sense if the element is following your finger as you drag it.
Is this a bug, or is there a way to disable this behavior without removing the other "interactive" animations?
P.S. The shiny border around the elements seems to be a rounded rectangle or capsule, but the actual element's shape seems to be stretched. That also appears to be a bug.
.navigationDestination(isPresented) hangs after reboot (when called within 2 minutes of reboot) in watchOS when destination view contains @Environment(.dismiss).
Feedback: FB21077151
Second button hangs after reboot. Hangs in watchOS 26.0 and 26.4 on a physical device.
struct ContentView: View {
@State var presentView1 : Bool = false
@State var presentView2 : Bool = false
var body: some View {
NavigationStack {
VStack {
Button("Show View 1") {
presentView1.toggle()
}
Button("Show View 2") {
presentView2.toggle()
}
}
.navigationDestination(isPresented: $presentView1, destination: {TestView1()})
.navigationDestination(isPresented: $presentView2, destination: {TestView2()})
}
}
}
struct TestView1: View {
var body: some View {
Text("View 1")
}
}
struct TestView2: View {
@Environment(\.dismiss) var dismiss
var body: some View {
Text("View 2")
}
}
I’ve encountered an aspect of the Liquid Glass effect in SwiftUI that seems a bit odd: the Liquid Glass interaction appears to ignore regular hit-testing behavior.
The following sample shows a button with hit testing disabled:
@main
struct LiquidGlassHitTestDemo: App {
var body: some Scene {
WindowGroup {
Button("Liquid") {
fatalError("Never called.")
}
.buttonStyle(.glassProminent)
.allowsHitTesting(false)
}
}
}
As expected, the button’s action is never called. However, the interactive glass effect still responds to touch events:
What’s even more surprising is that the UIKit equivalent behaves differently:
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(
configuration: .prominentGlass(),
primaryAction: UIAction(
title: "Liquid",
handler: { action in
print("Never called.")
}
)
)
view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
button.isUserInteractionEnabled = false
}
}
In this case, the effect is not interactive at all. Similarly, if a UIViewController’s root view overrides hitTest(_:with:) to always return nil, the Liquid Glass effect does not react to touch events whatsoever.
The only way I’ve found to “properly” disable the glass interactivity in SwiftUI is to use the .disabled(true) modifier. However, this also changes the button’s appearance, which is not always desirable.
Is this expected behavior, or could this be a bug? Am I missing something about how Liquid Glass interaction is implemented in SwiftUI?