Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

Posts under SwiftUI tag

200 Posts

Post

Replies

Boosts

Views

Activity

Reshield apps after certain time?
So I have been working with the screen time api. however I still cant get it to work to reshield certain apps after a certain time because for example Dispatch Queue just gets terminated after a certain time. This is my code right now but the reshielding doesn't get called. Please help I have been working on this since weeks and weeks. import ManagedSettings import DeviceActivity import Foundation class ShieldActionExtension: ShieldActionDelegate { let store = ManagedSettingsStore() let center = DeviceActivityCenter() override func handle(action: ShieldAction, for application: ApplicationToken, completionHandler: @escaping (ShieldActionResponse) -> Void) { switch action { case .primaryButtonPressed: // Unshield the app store.shield.applications?.remove(application) // Encode and persist ApplicationToken if let encoded = try? PropertyListEncoder().encode([application]) { UserDefaults(suiteName: "group.Organization.BrainRipe.cmonnow")?.set(encoded, forKey: "StoredApplicationTokens") } let unshieldDurationMinutes = 2 let now = Date() guard let endDate = Calendar.current.date(byAdding: .minute, value: unshieldDurationMinutes, to: now) else { completionHandler(.close) return } let activityName = DeviceActivityName("com.myapp.shield.reapply") let schedule = DeviceActivitySchedule( intervalStart: Calendar.current.dateComponents([.hour, .minute], from: now), intervalEnd: Calendar.current.dateComponents([.hour, .minute], from: endDate), repeats: false ) do { try center.startMonitoring(activityName, during: schedule) } catch { print("Error starting monitoring: \(error)") } completionHandler(.close) case .secondaryButtonPressed: completionHandler(.defer) @unknown default: fatalError("Unhandled ShieldAction case.") } } } import DeviceActivity import ManagedSettings import Foundation // Optionally override any of the functions below. // Make sure that your class name matches the NSExtensionPrincipalClass in your Info.plist. class DeviceActivityMonitorExtension: DeviceActivityMonitor { let store = ManagedSettingsStore() override func intervalDidStart(for activity: DeviceActivityName) { super.intervalDidStart(for: activity) // Handle the start of the interval. } override func intervalDidEnd(for activity: DeviceActivityName) { guard let data = UserDefaults(suiteName: "group.Organization.BrainRipe.cmonnow")?.data(forKey: "StoredApplicationTokens"), let tokens = try? PropertyListDecoder().decode([ApplicationToken].self, from: data) else { return } let tokenSet = Set(tokens) if store.shield.applications == nil { store.shield.applications = tokenSet } else { store.shield.applications?.formUnion(tokenSet) } // Clear tokens after use UserDefaults(suiteName: "group.Organization.BrainRipe.cmonnow")?.removeObject(forKey: "StoredApplicationTokens") } }
1
0
118
May ’25
A proper design approach for implementing a data logger using BLE in an iOS app.
Thank you for always reading my questions. This time, I'd like to ask some specific questions to gain a deeper understanding of iOS CoreBluetooth. In the previous question, we learned that although iOS can perform BLE scanning in the background, it is not suitable for use as a data logger. I was also taught that when using it as a data logger, the iOS app should use GATT communication, and that instead of reading data from the device one by one, it is recommended to store large amounts of data on the device and connect at an appropriate time (such as when the iOS app enters the foreground) to retrieve the data all at once. My requirements are the same as last time. I want to send data from a device equipped with some kind of sensor via BLE and display it in a graph in the iOS app. Data should be acquired every few to tens of seconds and reflected immediately in the graph. Measurements may take up to 24 hours at most. I would like to avoid making any major changes to the device. Also, it is unclear whether there will be enough memory for the data logger for 24 hours. Therefore, I am first looking for an appropriate communication method for the iOS app. iOS is smart and convenient, so I think users will check the measurement status every time they use this iOS app.Therefore, I want to be able to check the changes from the start of measurement to the present in a graph as soon as the app is launched. I would like to measure data from multiple devices (e.g. 5 devices) at the same time. I have a question based on the above requirements. When thinking about the best way to avoid making changes to the device, the only way I could come up with, as someone with insufficient iOS technology, is to keep the connection open via GATT communication and continue to obtain data. However, does iOS GATT communication have any limitations in this regard? Will the OS automatically disconnect GATT communication at a certain time? Also, if that happens, is there a way to automatically reconnect and obtain the data? Is it possible to smoothly obtain data using iOS GATT communication without any particular restrictions even in the background? Are any other permissions required? Regarding the sixth requirement. Until last time, with BLE scanning, even if there were multiple devices, the iOS app could measure the data for as many devices as it wanted, but this time, how many devices can be read? In the case of GATT communication with iOS CoreBluetooth, can multiple devices maintain a long connection? Or is it basically better to have one device per connection when creating such an app for iOS? I would like to know if there are any restrictions or points to be careful of when using GATT communication with multiple devices. I'm sorry for broadening my question, but if neither question 1 nor question 2 works, it will put a burden on the design of the device. If data is stored on the device, is it possible to automatically and periodically connect to the device at a set time interval (for example, once an hour, allowing for some margin of error) when the iOS app is in the background, and obtain log data from the device? If you can think of any other best methods, please feel free to let me know. Also, I'd be happy if you could reply with any reference materials or URLs. Please note that our response may be delayed.
0
0
119
May ’25
Navigation broken in iOS 18.4
All of a sudden, after iOS 18.4 was released, I am having tons of navigation problems in my app in production. Buttons navigating to empty pages, views seeming to 'freeze', top navigation bar mismatched with the content of the page. It seems that iOS 18.4 broke a critical piece of UIKit + SwiftUI bridging functionality that my project relies on. ** Originally posted in 'Core OS' topic but realized 'UI Frameworks > General' made more sense. My bad. ** My application is written with both UIKit and SwiftUI components. Here is a breakdown of my setup: UIApplicationDelegate > UIWindow > rootViewController of window is a UITabBarController > each tab is a UINavigationController rootViewController of nav controller is a UIHostingController > rootView of the hosting controller is a SwiftUI View In my SwiftUI views, I have been using NavigationLink for horizontal 'push' style navigation in my SwiftUI views. I do not use NavigationView, I only rely on the bridging capabilities of UINavigationController to action on my NavigationLinks. This has never been an issue, until iOS 18.4 was released. Now, when running iOS 18.4, I am having all sorts of unexpected behavior in the UI. I will break down 2 of these use cases here: Use case A: In one of my SwiftUI views, I have a ForEach for which each element's view is a NavigationLink. This is using the NavigationLink(_ destination:,label:) initializer. Navigating forward from here works/looks normal. However, once I try to navigate backward from that destination (tap the 'Back' button in top left), the view goes blank and the navigation bar at the top of the page (which is maintained by the UINavigationController instance) does not change. If I call popToRootViewController on that nav controller, the navigation bar at the top of the page returns to its normal state, but the view is still blank. It is not until after I have called popToRootViewController, and then navigate to a different tab of the UITabBarController and return to the initial tab, does the SwiftuI content view (the one with the ForEach) finally redraw and the view hierarchy is restored. Here is a warning that is logged in the console when I tap the 'Back ' button: Top view controller's view unexpectedly not in window for navigation transition. Skipping layout. nav = <UINavigationController: 0x1110bbe00>, topVC = <TtGC7SwiftUI19UIHostingControllerV5MyApp10MyPage: 0x106814e00> EDIT: If I replace the NavigationLink with a call to UINavigationController.pushViewController, I am still seeing the exact same behavior. Pressing back button makes the view empty > need to pop to root view controller and switch tabs in order to restore the view. Use case B Another instance of this issue happens whenever I try to use a NavigationLink inside of a view that itself was the destination of a NavigationLink in its parent view (i.e.: Root view > detail view > sub-detail view). For example, take the detail view destination in use case A. I have tapped a NavigationLink from the ForEach and landed on the detail view. Again, so far things work/look normal. Now, if I tap on another NavigationLink from that detail view, the view does not transition to the new page. The top navigation bar does transition, and shows the title and actions associated with this second destination. However, the view of this second destination is not displayed. It is worth noting that the same warning I mentioned above is also logged when I tap the NavigationLink to navigate to this second destination. Top view controller's view unexpectedly not in window for navigation transition. Skipping layout. nav = <UINavigationController: 0x109859400>, topVC = <TtGC7SwiftUI19UIHostingControllerVVS_19BridgedPresentation8RootView: 0x300ab8000> Strangely, if I switch to a different tab of the UITabBarController and back to the initial tab, this second destination's view is successfully rendered. It seems that switching tabs in this UITabBarController is calling something in either SwiftUI or UIKit that is redrawing my views. Conclusion This is a serious issue with UIKit + SwiftUI bridging support. I have never had problems like this until devices started running iOS 18.4, and there is nothing in the iOS 18.4 changelog that suggests this was an intentional change. All of a sudden, after updating to the latest iOS version, my app is totally broken. I want to be clear that I'm not using deprecated NavigationLink methods in these instances. My app's minimum deployment target is iOS 16. I know that there are more modern navigation APIs like navigation stack, etc. I am looking for answers about my use case: whether it is officially unsupported as of iOS 18.4, whether this setup should be supported and this is indeed some sort of bug in iOS, or anything in-between. I'm happy to provide formatted code if needed for discussion purposes. This is about my entire app's view hierarchy so there are a lot of disparate lines of code that make up this problem.
3
7
495
May ’25
How to reopen a closed SwiftUI WindowGroup window programmatically without user interaction?
I’m building a macOS app using SwiftUI with a WindowGroup(id: "rootWindow") for the main UI. The app shows a countdown timer, and the timer continues to run even after the user closes the main window (clicks the red "X"). When the timer reaches 0, I want to automatically reopen that window and bring the app to the front. I’m currently using the following code to bring the app to the foreground and show the window when the app is still open (but not focused/resign active state): NSApp.activate(ignoringOtherApps: true) NSApp.windows.forEach { window in if window.identifier?.rawValue.starts(with: "rootWindow") { window.makeKeyAndOrderFront(nil) } } However, this doesn’t work when the window has been closed. At that point, NSApp.windows no longer contains my SwiftUI window, and I have no reference to recreate or reopen it. I also cannot use openWindow environment value as it requires a view. How can I programmatically reopen a SwiftUI WindowGroup window after it’s been closed, without requiring any user interaction (like clicking the Dock icon)?
2
0
82
May ’25
A basic DocumentGroup App presents two back "<" buttons on the navigation bar.
Please has anyone found a workaround for duplicate back buttons appearing on the toolbar of a ContentView launched from a DocumentGroup? The problem occurs with Xcode 14.0 running a basic DocumentGroup App on iOS 16.0. To reproduce, simply build a new project using the "Document App" template. Build and run in the iOS/iPadOS simulator or on an iOS/iPadOS device. Two back buttons appear. Only one functions. I've not found a way to eliminate the dud. This problem has occurred throughout the Xcode 14.0 beta program.
8
6
1.9k
May ’25
Cannot reassign worldTracking / planeDetection providers in my PlacementManager when switching environments
Environment Xcode: 16.2 VisionOS SDK 2.4 Swift 6.1 Targets: Apple Vision Pro (immersive space) Frameworks: ARKit, RealityKit, SwiftUI What I’m Trying to Do I have a view-model class PlacementManager that holds two AR providers: private var worldTracking: WorldTrackingProvider private var planeDetection: PlaneDetectionProvider I want to dynamically replace these providers in a setEnvironment(_:) method (so I can save/clear a JSON scene and restart ARKit). What’s Happening If I declare them as : private let worldTracking = WorldTrackingProvider() private let planeDetection = PlaneDetectionProvider() I get compile-errors when I later do: self.worldTracking = newWorldTracking // Cannot assign to property: 'worldTracking' is a 'let' constant If I change them to un-initialized vars: private var worldTracking: WorldTrackingProvider private var planeDetection: PlaneDetectionProvider then in my init() I get: self used in property access 'worldTracking' before all stored properties are initialized Code snipet @Observable final class PlacementManager : ObservableObject { private var worldTracking: WorldTrackingProvider private var planeDetection: PlaneDetectionProvider // … other props … @MainActor init() { // error: self.worldTracking used before init… planeAnchorHandler = PlaneAnchorHandler(rootEntity: root) persistenceManager = PersistenceManager( worldTracking: worldTracking, rootEntity: root ) // … } @MainActor func setEnvironment(env: Environnement) async { let newWorldTracking = WorldTrackingProvider() let newPlaneDetection = PlaneDetectionProvider() try await appState!.arkitSession.run( [ newWorldTracking, newPlaneDetection ] ) self.worldTracking = newWorldTracking self.planeDetection = newPlaneDetection // … } } What I’ve Tried Giving them default values at declaration (= WorldTrackingProvider()) Initializing them at the top of init() before any use Passing the new providers into arkitSession.run(...) My Question What is the recommended Swift-style pattern to declare and reassign these ARKit provider properties so that: They’re fully initialized before use in init(), and I can swap them out later in setEnvironment(...) without compiler errors? Any pointers (or links to forum threads / docs) would be greatly appreciated!
0
0
92
May ’25
Lock widget for pro-users
Hi, I have added widgets to my iOS app and I would like to make this feature only accessible to "pro" users that have made a non-consumable in-app purchase. Currently, I am doing the following: I store an "isUnlocked" property in the Keychain after the purchase is made I read data to be displayed in the widget and here I also query the Keychain and store whether the widget is unlocked I have no refresh policy, but only change the widget data on a significant time change a different view is displayed when the app is locked Some dummy code snippets: func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) { &#9;&#9;let entry = readContents() &#9;&#9;let timeline = Timeline(entries: [entry], policy: .never) &#9;&#9;completion(timeline) } struct WidgetEntryView: View { &#9;&#9;let entry: Provider.Entry     @Environment(\.widgetFamily) var family     @ViewBuilder     var body: some View {         switch family {         case .systemSmall:             if !entry.isUnlocked {                 LockedWidgetView()             } else if let event = entry.event {                 SmallWidgetEventView(event: event)             } else {                 NoDataWidgetView()             } ... func applicationSignificantTimeChange(_ application: UIApplication) { &#9;&#9;if #available(iOS 14.0, *) { &#9;&#9;&#9;&#9;WidgetCenter.shared.reloadAllTimelines() &#9;&#9;} ... However, 2 unexpected things happen: the view is refreshed intraday (not only at midnight i.e. at significant time change) sometimes the LockedWidgetView is displayed. Especially the latter is problematic, because it gives false information to a user that has already made the in-app purchase. How can I achieve my goal of only displaying info when the user has made the in-app purchase? Thanks in advance. P.S. Although it would not have my preference, I would also find it acceptable if the widget is only shown as option to add once the purchase is made. In other words, I was considering changing the Widget itself: struct MyWidget: Widget {     private var supportedFamilies: [WidgetFamily] = isUnlocked() ? [.systemSmall, .systemMedium] : [] but I believe I cannot re-initialise the widget from the app when the user makes the in-app purchase, because the only refresh option that I have is WidgetCenter.shared.reloadAllTimelines()
7
0
3.6k
May ’25
VisionOS NavigationStack background cannot be removed?
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.
4
2
964
Apr ’25
[SwiftUI] Gesture Conflict: simultaneousGesture Causes Incorrect Gesture Recognition in iOS 18
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.
0
0
78
Apr ’25
Help getting elements from SwiftData in AppIntent for widget
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?
0
0
74
Apr ’25
Custom @Observable RandomAcccessCollection List/ForEach issues
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 } }
1
0
80
Apr ’25
No screenshot files in XCResult files using Xcode 16.1
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
6
1
597
Apr ’25
[SwiftUI] SecureEntry Autofill in Dark Mode
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?
0
0
45
Apr ’25
I received hardly any response to my DTS ticket - What to do?
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!
1
0
81
Apr ’25
Live Activity animate without updating data
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?
0
0
120
Apr ’25
Different Build Schemes -> Error: -Onone Swift optimization level to use previews
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.
5
0
322
Apr ’25
Opening a New Tab with Text in a Document-Based App
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) } } } }
2
0
70
Apr ’25
SwiftData updates in the background are not merged in the main UI context
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 } }
1
1
754
Apr ’25
How to import large data from Server and save it to Swift Data
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 ?
2
0
95
Apr ’25
Scene for my "Application's Menu About "My Application""
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.
3
0
1k
Apr ’25