I have a simple example to demonstrate...
struct MyView: View {
var body: some View {
Text("WOW")
}
}
struct MyOtherView: View {
var body: some View {
NavigationStack {
Text("WOW")
}
}
}
On VisionOS, MyOtherView has a glass background effect that cannot be disabled. glassBackgroundEffect(displayMode: .never) .background(.clear), .foregroundColor(.clear), none of them work.
I then resorted to the SwiftUIIntrospect package to try set .clear on various child objects of the NavigationStack but nothing is working.
I am in control of my own glass containers. I have a couple with space between them, but with the NavigationStack it sets a background behind both of them ruining the effect.
This is what MyOtherView renders as:
I'm looking for it to be completely transparent except the text. Like the below layout.
For now I will have to roll my own navigation.
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
Subject: SwiftUI Gesture Conflict in iOS 18: Simultaneous Recognition of Drag and Tap Gestures
Description:
In SwiftUI on iOS 18 and above, we've identified an issue with gesture handling that affects user experience. When implementing .simultaneousGesture(DragGesture()), the system incorrectly recognizes and processes both drag and tap gestures concurrently, resulting in unintended behavior.
Technical Details:
Environment: SwiftUI, iOS 18+
Issue: Simultaneous recognition of horizontal drag gestures and vertical scroll/tap gestures
Current Behavior: Both vertical and horizontal scrolling occur simultaneously when using .simultaneousGesture(DragGesture())
Expected Behavior: Gestures should be properly disambiguated to prevent concurrent scrolling in multiple directions
Impact:
This behavior significantly impacts user experience, particularly in custom carousel implementations and other UI components that rely on precise gesture handling. The simultaneous recognition of both gestures creates a confusing and unpredictable interaction pattern.
Steps to Reproduce:
Create a SwiftUI view with horizontal scrolling (e.g., custom carousel)
Implement .simultaneousGesture(DragGesture())
Add tap gesture recognition to child views
Run on iOS 18
Attempt to scroll horizontally
Observed Result:
Both horizontal dragging and vertical scrolling/tapping are recognized and processed simultaneously, creating an inconsistent user experience.
Expected Result:
The system should properly disambiguate between horizontal drag gestures and vertical scroll/tap gestures, allowing only one type of gesture to be recognized at a time based on the user's intent.
Please let me know if you need any additional information or reproduction steps.
Hello,
I am trying to get the elements from my SwiftData databse in the configuration for my widget.
The SwiftData model is the following one:
@Model
class CountdownEvent {
@Attribute(.unique) var id: UUID
var title: String
var date: Date
@Attribute(.externalStorage) var image: Data
init(id: UUID, title: String, date: Date, image: Data) {
self.id = id
self.title = title
self.date = date
self.image = image
}
}
And, so far, I have tried the following thing:
AppIntent.swift
struct ConfigurationAppIntent: WidgetConfigurationIntent {
static var title: LocalizedStringResource { "Configuration" }
static var description: IntentDescription { "This is an example widget." }
// An example configurable parameter.
@Parameter(title: "Countdown")
var countdown: CountdownEntity?
}
Countdowns.swift, this is the file with the widget view
struct Provider: AppIntentTimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), configuration: ConfigurationAppIntent())
}
func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {
SimpleEntry(date: Date(), configuration: configuration)
}
func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, configuration: configuration)
entries.append(entry)
}
return Timeline(entries: entries, policy: .atEnd)
}
// func relevances() async -> WidgetRelevances<ConfigurationAppIntent> {
// // Generate a list containing the contexts this widget is relevant in.
// }
}
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationAppIntent
}
struct CountdownsEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("Time:")
Text(entry.date, style: .time)
Text("Title:")
Text(entry.configuration.countdown?.title ?? "Default")
}
}
}
struct Countdowns: Widget {
let kind: String = "Countdowns"
var body: some WidgetConfiguration {
AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in
CountdownsEntryView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
}
}
}
CountdownEntity.swift, the file for the AppEntity and EntityQuery structs
struct CountdownEntity: AppEntity, Identifiable {
var id: UUID
var title: String
var date: Date
var image: Data
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(title: "\(title)")
}
static var defaultQuery = CountdownQuery()
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Countdown"
init(id: UUID, title: String, date: Date, image: Data) {
self.id = id
self.title = title
self.date = date
self.image = image
}
init(id: UUID, title: String, date: Date) {
self.id = id
self.title = title
self.date = date
self.image = Data()
}
init(countdown: CountdownEvent) {
self.id = countdown.id
self.title = countdown.title
self.date = countdown.date
self.image = countdown.image
}
}
struct CountdownQuery: EntityQuery {
typealias Entity = CountdownEntity
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Countdown Event")
static var defaultQuery = CountdownQuery()
@Environment(\.modelContext) private var modelContext // Warning here: Stored property '_modelContext' of 'Sendable'-conforming struct 'CountdownQuery' has non-sendable type 'Environment<ModelContext>'; this is an error in the Swift 6 language mode
func entities(for identifiers: [UUID]) async throws -> [CountdownEntity] {
let countdownEvents = getAllEvents(modelContext: modelContext)
return countdownEvents.map { event in
return CountdownEntity(id: event.id, title: event.title, date: event.date, image: event.image)
}
}
func suggestedEntities() async throws -> [CountdownEntity] {
// Return some suggested entities or an empty array
return []
}
}
CountdownsManager.swift, this one just has the function that gets the array of countdowns
func getAllEvents(modelContext: ModelContext) -> [CountdownEvent] {
let descriptor = FetchDescriptor<CountdownEvent>()
do {
let allEvents = try modelContext.fetch(descriptor)
return allEvents
}
catch {
print("Error fetching events: \(error)")
return []
}
}
I have installed it in my phone and when I try to edit the widget, it doesn't show me any of the elements I have created in the app, just a loading dropdown for half a second:
What am I missing here?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
SwiftUI
WidgetKit
App Intents
SwiftData
I'm trying to understand the behavior I'm seeing here. In the following example, I have a custom @Observable class that adopts RandomAccessCollection and am attempting to populate a List with it.
If I use an inner collection property of the instance (even computed as this shows), the top view identifies additions to the list.
However, if I just use the list as a collection in its own right, it detects when a change is made, but not that the change increased the length of the list. If you add text that has capital letters you'll see them get sorted correctly, but the lower list retains its prior count. The choice of a List initializer with the model versus an inner ForEach doesn't change the outcome, btw.
If I cast that type as an Array(), effectively copying its contents, it works fine which leads me to believe there is some additional Array protocol conformance that I'm missing, but that would be unfortunate since I'm not sure how I would have known that. Any ideas what's going on here? The new type can be used with for-in scenarios fine and compiles great with List/ForEach, but has this issue. I'd like the type to not require extra nonsense to be used like an array here.
import SwiftUI
fileprivate struct _VExpObservable6: View {
@Binding var model: ExpModel
@State private var text: String = ""
var body: some View {
NavigationStack {
VStack(spacing: 20) {
Spacer()
.frame(height: 40)
HStack {
TextField("Item", text: $text)
.textFieldStyle(.roundedBorder)
.textContentType(.none)
.textCase(.none)
Button("Add Item") {
guard !text.isEmpty else { return }
model.addItem(text)
text = ""
print("updated model #2 using \(Array(model.indices)):")
for s in model {
print("- \(s)")
}
}
}
InnerView(model: model)
OuterView(model: model)
}
.listStyle(.plain)
.padding()
}
}
}
// - displays the model data using an inner property expressed as
// a collection.
fileprivate struct InnerView: View {
let model: ExpModel
var body: some View {
VStack {
Text("Model Inner Collection:")
.font(.title3)
List {
ForEach(model.sorted, id: \.self) { item in
Text("- \(item)")
}
}
.border(.darkGray)
}
}
}
// - displays the model using the model _as the collection_
fileprivate struct OuterView: View {
let model: ExpModel
var body: some View {
VStack {
Text("Model as Collection:")
.font(.title3)
// - the List/ForEach collections do not appear to work
// by default using the @Observable model (RandomAccessCollection)
// itself, unless it is cast as an Array here.
List {
// ForEach(Array(model), id: \.self) { item in
ForEach(model, id: \.self) { item in
Text("- \(item)")
}
}
.border(.darkGray)
}
}
}
#Preview {
@Previewable @State var model = ExpModel()
_VExpObservable6(model: $model)
}
@Observable
fileprivate final class ExpModel: RandomAccessCollection {
typealias Element = String
var startIndex: Int { 0 }
var endIndex: Int { sorted.count }
init() {
_listData = ["apple", "yellow", "about"]
}
subscript(_ position: Int) -> String {
sortedData()[position]
}
var sorted: [String] {
sortedData()
}
func addItem(_ item: String) {
_listData.append(item)
_sorted = nil
}
private var _listData: [String]
private var _sorted: [String]?
private func sortedData() -> [String] {
if let ret = _sorted { return ret }
let ret = _listData.sorted()
_sorted = ret
return ret
}
}
Hello,
I am using Xcode 16.1 (16B40) on MacOS Sequoia 15.1.0 using a Macbook pro M1 Max
I am developing an app for iOS 17 and 18 using SwiftUI
I created UITests to take the screenshots for the appStore on the simulator
The tests run well and all of them are succeded
The problem appears when I try to get the screenshot files from the xcresult files after the test. There is not any screenshot inside it.
I found a data folder and a Info.plist file. In the data folder there are a lot of files with this pattern data.03zD4C6IGFFthK14NwA8mNvcwFHT16g6Tl40Tl1YmBC1bNh6d0YIcnWKyUaQPDXoa8fYo6C3Xcv8xvMtE3_NEXA== and other files with this pattern refs.03zD4C6IGFFthK14NwA8mNvcwFHT16g6Tl40Tl1YmBC1bNh6d0YIcnWKyUaQPDXoa8fYo6C3Xcv8xvMtE3_NEXA==
Ok, I tryed to use fastlane to automatize the screenshots but the problem is still present. The xcresult files have not any png file.
I had no problems doing this action (getting screenshots from a xcresult file) in previous versions of MacOS and Xcode in my current machine.
I just updated my machine to MacOS Sequoia 15.1.1 and the problem is still present
Honestly I don't know how to fix this situation.
With Xcode 15 I had not any problem with that but I am not sure if Xcode 16.0 was runing without problems because I didn't need to use this functionality in those months
Here is my code for a UITest:
import XCTest
final class ScreenshotsUITests: XCTestCase {
let app = XCUIApplication()
let device = "iPhone16"
override func setUpWithError() throws {
continueAfterFailure = true
}
override func tearDownWithError() throws {}
@MainActor
func testEnglishScreens() throws {
let lang = "en"
app.launchArguments.append("UITestMode")
app.launchArguments += ["-AppleLanguages", "(en)"]
app.launchArguments += ["-AppleLocale", "en_US"]
app.launch()
executeTestsForMenus(lang: lang, backLabel: "Back")
executeTestForMatch(lang: lang)
}
@MainActor
func testSpanishScreens() throws {
let lang = "es"
app.launchArguments.append("UITestMode")
app.launchArguments += ["-AppleLanguages", "(es)"]
app.launchArguments += ["-AppleLocale", "es_ES"]
app.launch()
executeTestsForMenus(lang: lang, backLabel: "Atrás")
executeTestForMatch(lang: lang)
}
private func executeTestForMatch(lang: String) {
let startButton = app.buttons["start-button"]
startButton.tap()
let key4 = app.buttons["key-4"]
XCTAssertTrue(key4.waitForExistence(timeout: 30), "Key 4 in match screen is not found")
key4.tap()
let key2 = app.buttons["key-2"]
XCTAssertTrue(key2.exists, "Key 2 in match screen is not found")
key2.tap()
makeScreenShot("playing", lang: lang)
let closeButton = app.buttons["close-button"]
XCTAssertTrue(closeButton.exists, "Close button in match screen is not found")
closeButton.tap()
}
private func executeTestsForMenus(lang: String, backLabel: String) {
let mainHeader = app.staticTexts["Math match"]
XCTAssertTrue(mainHeader.exists, "Header in main screen is not found")
makeScreenShot("mainMenu", lang: lang)
let settingsButton = app.buttons["settings-button"]
XCTAssertTrue(settingsButton.exists, "Settings button in main screen is not found")
settingsButton.tap()
makeScreenShot("Settings", lang: lang)
let backButton = app.buttons[backLabel]
XCTAssertTrue(backButton.exists, "Back button in match screen is not found")
backButton.tap()
let helpButton = app.buttons["help-button"]
XCTAssertTrue(helpButton.exists, "Help button in main screen is not found")
helpButton.tap()
makeScreenShot("Help", lang: lang)
backButton.tap()
let scoreButton = app.buttons["score-button"]
XCTAssertTrue(scoreButton.exists, "Scores button in main screen is not found")
scoreButton.tap()
makeScreenShot("Scores", lang: lang)
backButton.tap()
let playButton = app.buttons["play-button"]
XCTAssertTrue(playButton.exists, "Play button in main screen is not found")
playButton.tap()
makeScreenShot("matchBuilder", lang: lang)
let startButton = app.buttons["start-button"]
XCTAssertTrue(startButton.exists, "Start button in match builder screen is not found")
}
private func makeScreenShot(_ name: String, lang: String) {
takeScreenshot(app, named: "\(lang)-\(name)-\(device)")
}
}
import XCTest
extension XCTestCase {
func takeScreenshot(_ app: XCUIApplication, named name: String, fullScreen: Bool = false) {
let screenshot: XCUIScreenshot
if fullScreen {
screenshot = app.windows.firstMatch.screenshot()
} else {
screenshot = XCUIScreen.main.screenshot()
}
let screenshotAttachment = XCTAttachment(
uniformTypeIdentifier: "public.png",
name: "screenshot-\(name).png",
payload: screenshot.pngRepresentation,
userInfo: nil)
screenshotAttachment.lifetime = .keepAlways
add(screenshotAttachment)
}
}
and here is the content of my testplan file:
{
"configurations" : [
{
"id" : "35BC7C0B-9A5A-4027-9F30-36958C4C1AAF",
"name" : "Test Scheme Action",
"options" : {
"preferredScreenCaptureFormat" : "screenshot",
"testExecutionOrdering" : "random",
"uiTestingScreenshotsLifetime" : "keepAlways",
"userAttachmentLifetime" : "keepAlways"
}
}
],
"defaultOptions" : {
"targetForVariableExpansion" : {
"containerPath" : "container:myAppProject.xcodeproj",
"identifier" : "B27D1B022CA00314001A259B",
"name" : "MyAppProject"
}
},
"testTargets" : [
{
"parallelizable" : true,
"target" : {
"containerPath" : "container:MyAppProject.xcodeproj",
"identifier" : "B27D1B122CA00315001A259B",
"name" : "MyAppProjectTests"
}
},
{
"parallelizable" : true,
"target" : {
"containerPath" : "container:MyAppProject.xcodeproj",
"identifier" : "B27D1B1C2CA00315001A259B",
"name" : "MyAppProjectUITests"
}
}
],
"version" : 1
}
I made tests with old projects in my machine and those projects have the same problem with screenshot files in the xcresult bundles
I don't know if the problem is in my machine, my Xcode, MacOS or other ting. I don't know how to fix this problem
Please, can anyone help me?
Thanks in advance
When using New Password Autofill in Dark Mode, it appears that SecureEntry sets the background color to white and applies a yellow-ish overlay, but doesn't adapt the foreground text color accordingly. This gives the illusion that the SecureEntry field is empty, as we have white text on a white background.
Is there a holistic and SwiftUI-native way of fixing this?
About three weeks ago I submitted a DTS ticket (13097367) to receive code level support with a potential SwiftUI bug. At first I did not receive any response at all (beside the automatic confirmation that the ticket has been created).
Only after posting the question here, I got a reply from a DTS engineer. However, the proposed solution did not really solve the problem but only circumvents it (UI freezes when ScrollView reaches below SafeArea. Solution: Do not use ScrollView below SafeArea...)
I pointed out, that this does not really help me. Since then I did not receive any further response.
Is this normal? Is there something wrong with my ticket? Maybe it was closed by accident or something?
Thank you very much!
Is it actually possible to display animation (even a simple one) on Live Activity? But on these cases:
The main app is terminated - of course, I know I can use the main app to keep updating the Live Activity to make simple animations work, but in this case, the main app is killed.
Live Activity data is not updating - I also understand that the Live Activity can perform animations when its data is being update via push notification or other means, but the current case is the data is not being updated.
I’ve tried several ways to achieve this, but nothing seems to work.
Just when I was about to give up, I found this video from Apple’s official channel:
https://www.youtube.com/watch?v=m6WMwSj_EbA
At 4:14 in this video, you can see the text "Locating Driver" with the breathing animation. Could someone please help me understand how to implement that kind of animation in a Live Activity when:
The main app is not running, and
The Live Activity data is not updating?
I have a sample SwiftUI iOS app. As shown in the screenshot below, my project has three configurations: Debug, MyDebug, Release.
If I select the Debug or MyDebug scheme, I get a preview. But if I select the Release scheme, I get an error that says the following.
”***.app” needs -Onone Swift optimization level to use previews (current setting is -O)
, where *** is the app name.
It probably has nothing to do with the Preview error, but the Info.plist has a dictionary such that the key name is devMode, and the value is $(DEVMODE). And I have a user-defined setting as shown below.
My ContentView has the following.
import SwiftUI
struct ContentView: View {
@State private var state: String = ""
var body: some View {
VStack {
Text("Hello, world!: \(state)")
}
.onAppear {
if let devMode = Bundle.main.object(forInfoDictionaryKey: "devMode") as? String {
print("Development mode: \(devMode)")
state = devMode
}
if let path = Bundle.main.path(forResource: "Info", ofType: "plist") {
if let dict = NSDictionary(contentsOfFile: path) {
print("**** \(dict)")
}
}
#if DEBUG
print("Debug")
#elseif MYDEBUG
print("MyDebug")
#else
print("Que?")
#endif
}
}
}
#Preview {
ContentView()
}
So my question is how I get the preview for all three build schemes? Muchos thankos.
I have a sample document-based application for macOS. According to this article (https://jujodi.medium.com/adding-a-new-tab-keyboard-shortcut-to-a-swiftui-macos-application-56b5f389d2e6), you can create a new tab programmatically. It works. Now, my question is whether you can open a tab with some data. Is that possible under the SwiftUI framework? I could do it in Cocoa. Hopefully, we can do it in SwiftUI as well. Muchos thankos.
import SwiftUI
@main
struct SomeApp: App {
var body: some Scene {
DocumentGroup(newDocument: SomeDocument()) { file in
ContentView(document: file.$document)
}
}
}
import SwiftUI
struct ContentView: View {
@Binding var document: SomeDocument
var body: some View {
VStack {
TextEditor(text: $document.text)
Button {
createNewTab()
} label: {
Text("New tab")
.frame(width: 64)
}
}
}
}
extension ContentView {
private func createNewTab() {
if let currentWindow = NSApp.keyWindow,
let windowController = currentWindow.windowController {
windowController.newWindowForTab(nil)
if let newWindow = NSApp.keyWindow,
currentWindow != newWindow {
currentWindow.addTabbedWindow(newWindow, ordered: .above)
}
}
}
}
Hello,
SwiftData is not working correctly with Swift Concurrency. And it’s sad after all this time.
I personally found a regression. The attached code works perfectly fine on iOS 17.5 but doesn’t work correctly on iOS 18 or iOS 18.1.
A model can be updated from the background (Task, Task.detached or ModelActor) and refreshes the UI, but as soon as the same item is updated from the View (fetched via a Query), the next background updates are not reflected anymore in the UI, the UI is not refreshed, the updates are not merged into the main.
How to reproduce:
Launch the app
Tap the plus button in the navigation bar to create a new item
Tap on the “Update from Task”, “Update from Detached Task”, “Update from ModelActor” many times
Notice the time is updated
Tap on the “Update from View” (once or many times)
Notice the time is updated
Tap again on “Update from Task”, “Update from Detached Task”, “Update from ModelActor” many times
Notice that the time is not update anymore
Am I doing something wrong? Or is this a bug in iOS 18/18.1?
Many other posts talk about issues where updates from background thread are not merged into the main thread. I don’t know if they all are related but it would be nice to have
1/ bug fixed, meaning that if I update an item from a background, it’s reflected in the UI, and
2/ proper documentation on how to use SwiftData with Swift Concurrency (ModelActor). I don’t know if what I’m doing in my buttons is correct or not.
Thanks,
Axel
import SwiftData
import SwiftUI
@main
struct FB_SwiftData_BackgroundApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: Item.self)
}
}
}
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@State private var simpleModelActor: SimpleModelActor!
@Query private var items: [Item]
var body: some View {
NavigationView {
VStack {
if let firstItem: Item = items.first {
Text(firstItem.timestamp, format: Date.FormatStyle(date: .omitted, time: .standard))
.font(.largeTitle)
.fontWeight(.heavy)
Button("Update from Task") {
let modelContainer: ModelContainer = modelContext.container
let itemID: Item.ID = firstItem.persistentModelID
Task {
let context: ModelContext = ModelContext(modelContainer)
guard let itemInContext: Item = context.model(for: itemID) as? Item else { return }
itemInContext.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
try context.save()
}
}
.buttonStyle(.bordered)
Button("Update from Detached Task") {
let container: ModelContainer = modelContext.container
let itemID: Item.ID = firstItem.persistentModelID
Task.detached {
let context: ModelContext = ModelContext(container)
guard let itemInContext: Item = context.model(for: itemID) as? Item else { return }
itemInContext.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
try context.save()
}
}
.buttonStyle(.bordered)
Button("Update from ModelActor") {
let container: ModelContainer = modelContext.container
let persistentModelID: Item.ID = firstItem.persistentModelID
Task.detached {
let actor: SimpleModelActor = SimpleModelActor(modelContainer: container)
await actor.updateItem(identifier: persistentModelID)
}
}
.buttonStyle(.bordered)
Button("Update from ModelActor in State") {
let container: ModelContainer = modelContext.container
let persistentModelID: Item.ID = firstItem.persistentModelID
Task.detached {
let actor: SimpleModelActor = SimpleModelActor(modelContainer: container)
await MainActor.run {
simpleModelActor = actor
}
await actor.updateItem(identifier: persistentModelID)
}
}
.buttonStyle(.bordered)
Divider()
.padding(.vertical)
Button("Update from View") {
firstItem.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
}
.buttonStyle(.bordered)
} else {
ContentUnavailableView(
"No Data",
systemImage: "slash.circle", //
description: Text("Tap the plus button in the toolbar")
)
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
}
private func addItem() {
modelContext.insert(Item(timestamp: Date.now))
try? modelContext.save()
}
}
@ModelActor
final actor SimpleModelActor {
var context: String = ""
func updateItem(identifier: Item.ID) {
guard let item = self[identifier, as: Item.self] else {
return
}
item.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
try! modelContext.save()
}
}
@Model
final class Item: Identifiable {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
Here’s the situation:
• You’re downloading a huge list of data from iCloud.
• You’re saving it one by one (sequentially) into SwiftData.
• You don’t want the SwiftUI view to refresh until all the data is imported.
• After all the import is finished, SwiftUI should show the new data.
The Problem
If you insert into the same ModelContext that SwiftUI’s @Environment(.modelContext) is watching, each insert may cause SwiftUI to start reloading immediately.
That will make the UI feel slow, and glitchy, because SwiftUI will keep trying to re-render while you’re still importing.
How to achieve this in Swift Data ?
I am using SwiftUI to create an app and I have figured out how to present a scene for my preferences window. However I have yet to find a way to modify the "About "My App"" scene. I am not even sure how to ask the question on other forums because I keep getting informations on application menus.
I would like to find information on accessing/changing other menu entries in the menubar (in SwiftUI) an most specifically I would like to find out how to present a custom window (or at least custom information) when the user selects "About "My App""
I guess I don't need a solution but a pointer to documentation that will help me in my quest.
When attempting to replicate the tvOS Settings menu layout, where the screen is divided horizontally into two sections, placing a NavigationStack or a Form view on either side of the screen causes focusable views (such as Button, TextField, Toggle, etc.) to be visually clipped when they receive focus and apply the default scaling animation.
Specifically:
If the Form or NavigationStack is placed on the right side, the left edge of the focused view gets clipped.
If placed on the left side, the right edge of the focused view gets clipped.
This issue affects any focusable child view inside the Form or NavigationStack when focus scaling is triggered.
Example code:
struct TVAppMenuMainView: View {
var body: some View {
VStack {
Text("Settings Menu")
.font(.title)
HStack {
VStack {
Text("Left Pane")
}
.frame(width: UIScreen.main.bounds.width * 0.4) // represents only 40% of the screen
.frame(maxHeight: .infinity)
.padding(.bottom)
Divider()
NavigationStack {
Form { // All the buttons will get cut on the left side when each button is focused
Button("First Button"){}
Button("Second Button"){}
Button("Third Button"){}
Button("Forth Button"){}
}
}
}
.frame(maxHeight: .infinity)
.frame(maxWidth: .infinity)
}
.background(.ultraThickMaterial)
}
}
How it looks:
What I have tried:
.clipped modifiers
.ignoresSafeArea
Modifying the size manually
Using just a ScrollView with VStack works as intended, but as soon as NavigationStack or Form are added, the buttons get clipped.
This was tested on the latest 18.5 tvOS BETA
Hello,
I would like to report a critical issue with Arabic text rendering in SwiftUI apps on iOS and iPadOS.
When using Arabic as the default language (Right-to-Left - RTL), Arabic text appears reversed and disconnected inside several SwiftUI components like:
List
Section
TextField
Picker
Custom views (like StudentRowView)
Even though the environment is set to .layoutDirection(.rightToLeft), the dynamic Arabic text is not rendered properly. Static headers display correctly, but any dynamic content (student names, notes, field titles) becomes broken and unreadable.
Examples where the issue occurs:
AboutView.swift → Arabic text inside List and Section
SettingsView.swift → TextField placeholders and Picker options
StudentRowView.swift → Student names and grade field titles
Environment:
SwiftUI 5 (Xcode 15+)
iOS 17+
Reproducible 100% on both Simulator and real devices.
Expected Behavior:
Arabic text should appear properly connected, right-aligned, and readable without any manual workaround for each Text or TextField.
Workarounds Tried:
Manually setting .multilineTextAlignment(.trailing) (inefficient)
Wrapping every Text inside an HStack with Spacer (hacky)
Building custom UIKit views (defeats purpose of SwiftUI simplicity)
Formal Feedback:
I have submitted a Feedback Assistant report
We hope this issue will be prioritized and fixed to improve SwiftUI's support for Arabic and other RTL languages.
Thank you.
There seems to be a bug; when scrolling very quickly down a List, and then scrolling up at normal speed, scrolling becomes very janky and jumpy, often skipping one or two rows. This only happens on macOS.
I'm kind of surprised I've seen no one else mention this bug, as I can recreate it in a very simple Xcode Project. I'm wondering if anyone knows of a workaround?
Steps to reproduce:
Build and launch the code below
Very quickly scroll all the way down using the scrollbar
Scroll up at a normal speed, after a few rows it will get janky
Code:
struct MinimalAlbum: Identifiable {
let id: Int
let title: String
}
struct ContentView: View {
private let staticAlbums: [MinimalAlbum] = (0..<1000).map { i in
MinimalAlbum(id: i, title: "Album Title \(i)")
}
var body: some View {
List {
ForEach(staticAlbums) { album in
Text("Album ID: \(album.id) - \(album.title)")
.frame(height: 80) // Fixed height
}
}
}
}
I am a little lost. Why is Xcode complaining of this. Everything looks right here. I even removed my code and copy-pasted Apple's sample from here - https://developer.apple.com/documentation/swiftui/list
Clean built and still get this.
Not using List removes the error.
I'm playing with a simple document-based application with TextEditor for macOS. In Cocoa, NSViewController can call updateChangeCount(_:) to clear document changes in NSDocument. I wonder SwiftUI's View has access to the same function? Hopefully, I would like to manually set the change count to zero if the user clears text in TextEditor. I bet SwiftUI doesn't have it. Thanks.
import SwiftUI
struct ContentView: View {
@Binding var document: SampleDocumentApp
var body: some View {
VStack {
TextEditor(text: $document.text)
.onChange(of: document.text) { _, _ in
guard !document.text.isEmpty else {
return
}
// clear change count //
}
}
.frame(width: 360, height: 240)
}
}
Apologies in advance for the long post. I'm new to HomeKit and Matter but not to development, I'm trying to write a SwiftUI app for my smart home to store all of my HomeKit and Matter setup barcodes along with other bits of information.
The intention is to scan the QR codes with my App and then save that QR payload in a simple Database along with other manually entered device details. Example payloads:
X-HM://00GWIN0B5PHPG <-- Eufy V120 HomeKit Camera
MT:GE.01-C-03FOPP6B110 <-- Moes GU10 Matter Bulb
I have it 99% working, my app is even able to discern the manual pairing code from the above payloads. However one of the key feature of this is that I want to open a device entry in my app and tap the HomeKit or Matter code displayed in my app and and either:
a) Ideally pass it off to the Apple Home app to initiate pairing just like the native Camera App can.
b) Create a custom flow in my app using the HomeKit or Matter API's to initiate paring from within my app.
So ideally just like the flow that happens when you scan a setup QR with the normal camera and tap "Open in Home". However I want to trigger this flow with just knowing the Payload and not with scanning it via the camera.
I was hoping there might be something as simple as a URL scheme that I could call with the payload as a variable and it then deep links and switches to the Home app, but I haven't found any info relating to this that actually works.
This is some code I have tried with the HomeKit API but this also results in an error:
import HomeKit
func startHomePairing(with setupCode: String) {
// Handle HomeKit setup
guard let payload = HMAccessorySetupPayload(url: URL(string: setupCode)!) else {
print("Invalid HomeKit setup code or format.")
return
}
let setupRequest = HMAccessorySetupRequest()
setupRequest.payload = payload
let setupManager = HMAccessorySetupManager()
// Perform the setup request and handle the result
setupManager.performAccessorySetup(using: setupRequest) { result, error in
if let error = error {
// Error handling: print the error details
print("Error starting setup: \(error.localizedDescription)")
// Print more details for debugging
print("Full Error: \(error)")
} else {
// Success: pairing was successful
print("Successfully launched Home app for HomeKit setup.")
}
}
}
But when passing in the QR payloads above it give the following ..
HomeKit Code
[0CAB3B05] Failed to perform accessory setup using request: Error Domain=HMErrorDomain Code=17 "(null)"
Matter Code
Failed to create HMSetupAccessoryPayload from setup payload URL MT:GE.01-C-03FOPP6B110: Error Domain=HMErrorDomain Code=3 "(null)"
I have added the "HomeKit" and "Matter Allow Setup Payload" capabilities to my app, I have also ensured I have these in the .plist ..
<key>NSHomeKitUsageDescription</key>
<string>Access required to HomeKit to initiate pairing for new accessories</string>
I also added a call to ensure my app appears in the Settings / Privacy / HomeKit section. I originally thought was a seemingly simple task, but I am really struggling with how to make it work!
Nice to meet you,
I'm currently trying to create an app like a data logger using BLE.
When a user uses the above app, they will probably put the app in the background and lock their iPhone if they want to collect data for a long period of time.
Therefore, the app I want to create needs to continue scanning for BLE even when it goes into the background.
The purpose is to continue to obtain data from the same device at precise time intervals for a long period of time (24 hours).
In that case, can I use the above function to continue to read and record advertising data from the same device periodically (at intervals of 10 seconds, 1 minute, or 5 minutes) after the app goes into the background?
Any advice, no matter how small, is welcome.
Please feel free to reply.
Also, if you have the same question in this forum and it has already been answered, I would appreciate it if you could let me know.