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

Posts under SwiftUI tag

147 Posts

Post

Replies

Boosts

Views

Activity

scenePhase not behaving as expected on screen lock
Seeing weird sequences of changes when locking the screen when view is visable. .onChange(of: scenePhase) { phase in if phase == .active { if UIApplication.shared.applicationState == .active { print("KDEBUG: App genuinely became active") } else { print("KDEBUG: False active signal detected") } } else if phase == .inactive { print("KDEBUG: App became inactive") // Handle inactive state if needed } else if phase == .background { print("KDEBUG: App went to background") // Handle background state if needed } } seen: (locks screen) KDEBUG: App became inactive KDEBUG: App genuinely became active KDEBUG: App went to background expected (locks screen) KDEBUG: App became inactive KDEBUG: App went to background
2
0
117
Apr ’25
SwiftUI tvOS NavigationTransition and matchedTransitionSource
According to the docs tvOS 18+ supports the new NavigationTransition and the matchedTransitionSource and navigationTransition(.zoom(sourceID: id, in: namespace)) modifiers, however they don't seems to work. Taking the DestinationVideo project example from the latest WWDC the matchedTransitionSourceis marked with #if os(iOS) Is it supported by tvOS or is it for iOS only? https://developer.apple.com/documentation/swiftui/view/navigationtransition(_:) https://developer.apple.com/documentation/swiftui/view/matchedtransitionsource(id:in:configuration:)
2
0
68
Apr ’25
SwiftUI FileImporter errors
When using FileImporter in SwiftUI, the following error is always returned when closed; even if the user taps "Cancel" The view service did terminate with error: Error Domain=_UIViewServiceErrorDomain Code=1 "(null)" UserInfo={Terminated=disconnect method} Recreation rate is 10/10. It feels like a threading issue, but in SwiftUI we are leveraging the .fileImporter modifier, so we cannot hold on to the reference like we would in a class. Is there a different approach we should be using for this? Code for recreation import SwiftUI struct ContentView: View { @State private var fileURL: URL? @State private var showFileImporter: Bool = false var body: some View { VStack { if let fileURL { Text(fileURL.absoluteString) } Button { showFileImporter = true } label: { Text("Select PDF") } .fileImporter( isPresented: $showFileImporter, allowedContentTypes: [.pdf], allowsMultipleSelection: true ) { result in switch result { case .success(let files): files.forEach { file in let gotAccess = file.startAccessingSecurityScopedResource() if !gotAccess { return } fileURL = file file.stopAccessingSecurityScopedResource() } case .failure(let error): print(error) } } } } }
1
0
116
Apr ’25
Background Tasks runs foreground
Hello everyone! I'm having a problem with background tasks running in the foreground. When a user enters the app, a background task is triggered. I've written some code to check if the app is in the foreground and to prevent the task from running, but it doesn't always work. Sometimes the task runs in the background as expected, but other times it runs in the foreground, as I mentioned earlier. Could it be that I'm doing something wrong? Any suggestions would be appreciated. here is code: class BackgroundTaskService { @Environment(\.scenePhase) var scenePhase static let shared = BackgroundTaskService() private init() {} // MARK: - create task func createCheckTask() { let identifier = TaskIdentifier.check BGTaskScheduler.shared.getPendingTaskRequests { requests in if requests.contains(where: { $0.identifier == identifier.rawValue }) { return } self.createByInterval(identifier: identifier.rawValue, interval: identifier.interval) } } private func createByInterval(identifier: String, interval: TimeInterval) { let request = BGProcessingTaskRequest(identifier: identifier) request.earliestBeginDate = Date(timeIntervalSinceNow: interval) scheduleTask(request: request) } // MARK: submit task private func scheduleTask(request: BGProcessingTaskRequest) { do { try BGTaskScheduler.shared.submit(request) } catch { // some actions with error } } // MARK: background actions func checkTask(task: BGProcessingTask) { let today = Calendar.current.startOfDay(for: Date()) let lastExecutionDate = UserDefaults.standard.object(forKey: "lastCheckExecutionDate") as? Date ?? Date.distantPast let notRunnedToday = !Calendar.current.isDate(today, inSameDayAs: lastExecutionDate) guard notRunnedToday else { task.setTaskCompleted(success: true) createCheckTask() return } if scenePhase == .background { TaskActionStore.shared.getAction(for: task.identifier)?() } task.setTaskCompleted(success: true) UserDefaults.standard.set(today, forKey: "lastCheckExecutionDate") createCheckTask() } } And in AppDelegate: BGTaskScheduler.shared.register(forTaskWithIdentifier: "check", using: nil) { task in guard let task = task as? BGProcessingTask else { return } BackgroundTaskService.shared.checkNodeTask(task: task) } BackgroundTaskService.shared.createCheckTask()
1
0
1k
Apr ’25
ScrollView triggers (almost) endless View redrawing.
I am developing a MacOS app with a vertically oriented ScrollView. Inside that View I use a LazyVStack. In the LazyVStack I have a column of images. I want the images to occupy as much of the LazyVStack width as possible so I created a frame for the VStack with a maxWidth: .infinity. When the user grabs the edge of the window and drags it to reduce the window width, the Views of the window adjust themselves to fit the reduced space. This includes reducing the width of the images. I maintain a fixed aspect ratio for the images, so the height of the images is reduced too. My problem arises when the width of the images (and height) reduces to the point where the scroll bar is no longer needed because all of the images fit within the height of the ScrollView, and the ScrollView removes the scroll bar. That triggers a redraw of the images, with a slightly bigger size because the width used by the scroll bar is now available. When the the images get bigger they don't all fit within the height of the ScrollView anymore and the scrollbar is restored. That, of course, reduces the space available for the images, so they are reduced in size again - which then triggers the ScrollView to remove the scrollbar again. The whole thing goes into a spasm of flickering images (bigger and smaller) and scrollbar (off and on) until finally I get the dreaded error message: The window has been marked as needing another Display Window pass, but it has already had more Display Window passes than there are views in the window. There seems to be no way to prevent this behavior by setting an option on the ScrollView. It would be great if one could indicate that the scroll bar should always remain visible, or at least that the space occupied by the scroll bar remain, even if it is just empty. The only way I could solve this problem was to go through a somewhat involved calculation to set the image width in such a way that it still responds to window width changes (and some other size changes I allow in some of the other app's Views). This complication would not be necessary if there were better controls on the scroll bar. Is there a reason for not providing adequate controls for the ScrollView? Its uncontrollable behavior complicates the programming.
1
1
298
Apr ’25
Custom Trait with UITraitBridgedEnvironmentKey not writing back to UITraitCollection
Hello, In my SwiftUI App i'm trying to create a custom UI trait and a matching bridged SwiftUI environment key. I want to override the environment key in a swift view and then have that reflect in the current UITraitCollection. I'm following the pattern in the linked video but am not seeing the changes reflect in the current trait collection when I update the swift env value. I can't find anything online that is helping. Does anyone know what I am missing? https://developer.apple.com/videos/play/wwdc2023/10057/ // Setup enum CustomTheme: String, Codable { case theme1 = “theme1”, theme2 = “theme2” } struct customThemeTrait: UITraitDefinition { static let defaultValue = brand.theme1 static let affectsColorAppearance = true static let identifier = "com.appName.customTheme" } extension UITraitCollection { var customTheme: CustomTheme { self[customThemeTrait.self] } } extension UIMutableTraits { var customTheme: CustomTheme { get { self[customThemeTrait.self] } set { self[customThemeTrait.self] = newValue } } } private struct customThemeKey: EnvironmentKey { static let defaultValue: CustomTheme = .theme1 } extension customThemeKey: UITraitBridgedEnvironmentKey { static func read(from traitCollection: UITraitCollection) -> CustomTheme { traitCollection.customTheme } static func write(to mutableTraits: inout UIMutableTraits, value: CustomTheme) { mutableTraits.customTheme = value } } extension EnvironmentValues { var customTheme: CustomTheme { get { self[customThemeKey.self] } set { self[customThemeKey.self] = newValue } } } // Attempted Usage extension Color { static func primaryBackground() -> Color { UITraitCollection.current.customTheme == .theme1 ? Color.red : Color.blue } } struct ContentView: View { @State private var theme = .theme1 var body: some View { if (dataHasLoaded && themeIsSet) { HomeView() .environment(\.customTheme, theme) } else { SelectThemeView( theme: self.theme, setContentThemeHandler) } } func setContentThemeHandler(theme: customTheme) { self.theme = theme } } struct HomeView() { @Environment(\.customTheme) private var currentTheme: customTheme var body: some View { VStack { Text("currentTheme: \(currentTheme.rawValue)") .background(Color.primaryBackground()) Text("currentUITrait: \(UITraitCollection.current.customTheme.rawValue)") .background(Color.primaryBackground()) } } } OUTCOME: After selecting theme2 in the theme selector view and navigating to the homeView, the background is still red and the env and trait values print the following: currentTheme: theme2 currentUITrait: theme1 Can anyone help me identify what I am missing?
1
0
99
Apr ’25
XCODE Preview: XOJITError: Could not create code file directory for session: Permission denied
I keep running into the following issue when trying to run preview for my application in Xcode. FailedToLaunchAppError: Failed to launch app.a /Users/me/Library/Developer/Xcode/DerivedData/a-aloudjuytoewlldqjfxshbjydjeh/Build/Products/Debug/a.app ================================== | [Remote] JITError | | ================================== | | | [Remote] XOJITError | | | | XOJITError: Could not create code file directory for session: Permission denied`
3
0
208
Apr ’25
scenePhase not behaving as expected on screen lock
Seeing weird sequences of changes when locking the screen when view is visable. .onChange(of: scenePhase) { phase in if phase == .active { if UIApplication.shared.applicationState == .active { print("KDEBUG: App genuinely became active") } else { print("KDEBUG: False active signal detected") } } else if phase == .inactive { print("KDEBUG: App became inactive") // Handle inactive state if needed } else if phase == .background { print("KDEBUG: App went to background") // Handle background state if needed } } seen: (locks screen) KDEBUG: App became inactive KDEBUG: App genuinely became active KDEBUG: App went to background expected (locks screen) KDEBUG: App became inactive KDEBUG: App went to background
Replies
2
Boosts
0
Views
117
Activity
Apr ’25
SwiftUI tvOS NavigationTransition and matchedTransitionSource
According to the docs tvOS 18+ supports the new NavigationTransition and the matchedTransitionSource and navigationTransition(.zoom(sourceID: id, in: namespace)) modifiers, however they don't seems to work. Taking the DestinationVideo project example from the latest WWDC the matchedTransitionSourceis marked with #if os(iOS) Is it supported by tvOS or is it for iOS only? https://developer.apple.com/documentation/swiftui/view/navigationtransition(_:) https://developer.apple.com/documentation/swiftui/view/matchedtransitionsource(id:in:configuration:)
Replies
2
Boosts
0
Views
68
Activity
Apr ’25
SwiftUI FileImporter errors
When using FileImporter in SwiftUI, the following error is always returned when closed; even if the user taps "Cancel" The view service did terminate with error: Error Domain=_UIViewServiceErrorDomain Code=1 "(null)" UserInfo={Terminated=disconnect method} Recreation rate is 10/10. It feels like a threading issue, but in SwiftUI we are leveraging the .fileImporter modifier, so we cannot hold on to the reference like we would in a class. Is there a different approach we should be using for this? Code for recreation import SwiftUI struct ContentView: View { @State private var fileURL: URL? @State private var showFileImporter: Bool = false var body: some View { VStack { if let fileURL { Text(fileURL.absoluteString) } Button { showFileImporter = true } label: { Text("Select PDF") } .fileImporter( isPresented: $showFileImporter, allowedContentTypes: [.pdf], allowsMultipleSelection: true ) { result in switch result { case .success(let files): files.forEach { file in let gotAccess = file.startAccessingSecurityScopedResource() if !gotAccess { return } fileURL = file file.stopAccessingSecurityScopedResource() } case .failure(let error): print(error) } } } } }
Replies
1
Boosts
0
Views
116
Activity
Apr ’25
Background Tasks runs foreground
Hello everyone! I'm having a problem with background tasks running in the foreground. When a user enters the app, a background task is triggered. I've written some code to check if the app is in the foreground and to prevent the task from running, but it doesn't always work. Sometimes the task runs in the background as expected, but other times it runs in the foreground, as I mentioned earlier. Could it be that I'm doing something wrong? Any suggestions would be appreciated. here is code: class BackgroundTaskService { @Environment(\.scenePhase) var scenePhase static let shared = BackgroundTaskService() private init() {} // MARK: - create task func createCheckTask() { let identifier = TaskIdentifier.check BGTaskScheduler.shared.getPendingTaskRequests { requests in if requests.contains(where: { $0.identifier == identifier.rawValue }) { return } self.createByInterval(identifier: identifier.rawValue, interval: identifier.interval) } } private func createByInterval(identifier: String, interval: TimeInterval) { let request = BGProcessingTaskRequest(identifier: identifier) request.earliestBeginDate = Date(timeIntervalSinceNow: interval) scheduleTask(request: request) } // MARK: submit task private func scheduleTask(request: BGProcessingTaskRequest) { do { try BGTaskScheduler.shared.submit(request) } catch { // some actions with error } } // MARK: background actions func checkTask(task: BGProcessingTask) { let today = Calendar.current.startOfDay(for: Date()) let lastExecutionDate = UserDefaults.standard.object(forKey: "lastCheckExecutionDate") as? Date ?? Date.distantPast let notRunnedToday = !Calendar.current.isDate(today, inSameDayAs: lastExecutionDate) guard notRunnedToday else { task.setTaskCompleted(success: true) createCheckTask() return } if scenePhase == .background { TaskActionStore.shared.getAction(for: task.identifier)?() } task.setTaskCompleted(success: true) UserDefaults.standard.set(today, forKey: "lastCheckExecutionDate") createCheckTask() } } And in AppDelegate: BGTaskScheduler.shared.register(forTaskWithIdentifier: "check", using: nil) { task in guard let task = task as? BGProcessingTask else { return } BackgroundTaskService.shared.checkNodeTask(task: task) } BackgroundTaskService.shared.createCheckTask()
Replies
1
Boosts
0
Views
1k
Activity
Apr ’25
ScrollView triggers (almost) endless View redrawing.
I am developing a MacOS app with a vertically oriented ScrollView. Inside that View I use a LazyVStack. In the LazyVStack I have a column of images. I want the images to occupy as much of the LazyVStack width as possible so I created a frame for the VStack with a maxWidth: .infinity. When the user grabs the edge of the window and drags it to reduce the window width, the Views of the window adjust themselves to fit the reduced space. This includes reducing the width of the images. I maintain a fixed aspect ratio for the images, so the height of the images is reduced too. My problem arises when the width of the images (and height) reduces to the point where the scroll bar is no longer needed because all of the images fit within the height of the ScrollView, and the ScrollView removes the scroll bar. That triggers a redraw of the images, with a slightly bigger size because the width used by the scroll bar is now available. When the the images get bigger they don't all fit within the height of the ScrollView anymore and the scrollbar is restored. That, of course, reduces the space available for the images, so they are reduced in size again - which then triggers the ScrollView to remove the scrollbar again. The whole thing goes into a spasm of flickering images (bigger and smaller) and scrollbar (off and on) until finally I get the dreaded error message: The window has been marked as needing another Display Window pass, but it has already had more Display Window passes than there are views in the window. There seems to be no way to prevent this behavior by setting an option on the ScrollView. It would be great if one could indicate that the scroll bar should always remain visible, or at least that the space occupied by the scroll bar remain, even if it is just empty. The only way I could solve this problem was to go through a somewhat involved calculation to set the image width in such a way that it still responds to window width changes (and some other size changes I allow in some of the other app's Views). This complication would not be necessary if there were better controls on the scroll bar. Is there a reason for not providing adequate controls for the ScrollView? Its uncontrollable behavior complicates the programming.
Replies
1
Boosts
1
Views
298
Activity
Apr ’25
Custom Trait with UITraitBridgedEnvironmentKey not writing back to UITraitCollection
Hello, In my SwiftUI App i'm trying to create a custom UI trait and a matching bridged SwiftUI environment key. I want to override the environment key in a swift view and then have that reflect in the current UITraitCollection. I'm following the pattern in the linked video but am not seeing the changes reflect in the current trait collection when I update the swift env value. I can't find anything online that is helping. Does anyone know what I am missing? https://developer.apple.com/videos/play/wwdc2023/10057/ // Setup enum CustomTheme: String, Codable { case theme1 = “theme1”, theme2 = “theme2” } struct customThemeTrait: UITraitDefinition { static let defaultValue = brand.theme1 static let affectsColorAppearance = true static let identifier = "com.appName.customTheme" } extension UITraitCollection { var customTheme: CustomTheme { self[customThemeTrait.self] } } extension UIMutableTraits { var customTheme: CustomTheme { get { self[customThemeTrait.self] } set { self[customThemeTrait.self] = newValue } } } private struct customThemeKey: EnvironmentKey { static let defaultValue: CustomTheme = .theme1 } extension customThemeKey: UITraitBridgedEnvironmentKey { static func read(from traitCollection: UITraitCollection) -> CustomTheme { traitCollection.customTheme } static func write(to mutableTraits: inout UIMutableTraits, value: CustomTheme) { mutableTraits.customTheme = value } } extension EnvironmentValues { var customTheme: CustomTheme { get { self[customThemeKey.self] } set { self[customThemeKey.self] = newValue } } } // Attempted Usage extension Color { static func primaryBackground() -> Color { UITraitCollection.current.customTheme == .theme1 ? Color.red : Color.blue } } struct ContentView: View { @State private var theme = .theme1 var body: some View { if (dataHasLoaded && themeIsSet) { HomeView() .environment(\.customTheme, theme) } else { SelectThemeView( theme: self.theme, setContentThemeHandler) } } func setContentThemeHandler(theme: customTheme) { self.theme = theme } } struct HomeView() { @Environment(\.customTheme) private var currentTheme: customTheme var body: some View { VStack { Text("currentTheme: \(currentTheme.rawValue)") .background(Color.primaryBackground()) Text("currentUITrait: \(UITraitCollection.current.customTheme.rawValue)") .background(Color.primaryBackground()) } } } OUTCOME: After selecting theme2 in the theme selector view and navigating to the homeView, the background is still red and the env and trait values print the following: currentTheme: theme2 currentUITrait: theme1 Can anyone help me identify what I am missing?
Replies
1
Boosts
0
Views
99
Activity
Apr ’25
XCODE Preview: XOJITError: Could not create code file directory for session: Permission denied
I keep running into the following issue when trying to run preview for my application in Xcode. FailedToLaunchAppError: Failed to launch app.a /Users/me/Library/Developer/Xcode/DerivedData/a-aloudjuytoewlldqjfxshbjydjeh/Build/Products/Debug/a.app ================================== | [Remote] JITError | | ================================== | | | [Remote] XOJITError | | | | XOJITError: Could not create code file directory for session: Permission denied`
Replies
3
Boosts
0
Views
208
Activity
Apr ’25