Hi!
I have a rather complicated SwiftUI browser app with a WKWebView. There is an option to reload the website after a configurable amount of time. Starting with iOS 18, the app crashes after repeated reloads. How many reloads that are required depends on the device, sometimes 100, sometimes 1000.
Reloading is done via a timer that triggers the following code on the main thread:
let request = URLRequest(url: url, cachePolicy: policy)
self.parent.webView.load(request)
The URL is configurable and cachePolicy can be either .reloadIgnoringLocalAndRemoteCacheData or .useProtocolCachePolicy
How the crash affects the device also differs from device to device and from time to time. I have suffered from the following crashtypes:
App is killed
App is killed and Safari also stops working
App is killed and the whole OS is really slow
The WKWebView stops loading and hangs at 20%.
The device is rebooted
My app has an option to disable cache. Cache is disabled by setting cachePolicy to .reloadIgnoringLocalAndRemoteCacheData and by removing all cache in a rather complicated way.
Basicly i'm doing something like this:
dataStore.removeData(ofTypes: types, modifiedSince: Date.distantPast, completionHandler: nil)
if let klazz = NSClassFromString("Web" + "History"),
let clazz = klazz as AnyObject as? NSObjectProtocol {
if clazz.responds(to: Selector(("optional" + "Shared" + "History"))) {
if let webHistory = clazz.perform(Selector(("optional" + "Shared" + "History"))) {
let o = webHistory.takeUnretainedValue()
_ = o.perform(Selector(("remove" + "All" + "Items")))
}
}
}
if let cachesPath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first {
let contents = (try? FileManager.default.contentsOfDirectory(atPath: cachesPath)) ?? []
for file in contents {
if foldersToDelete.contains(file) {
let path = cachesPath.appending("/").appending(file)
do {
try FileManager.default.removeItem(atPath: path)
} catch {
print("Can't delete cache file: \(path), error: \(error.localizedDescription)")
}
}
}
}
The cache state affects the intensity of the crash. Disabling the cache shortens the time the app is working, while enabling the cache reduces the intensity of the bug.
Based on my investigation, I suspect that loading a website in a WKWebVew leaks memory in iOS 18. If the whole website needs to be requested (= caching off), it results in a more significant memory leak and a faster crash time.
Is this a known issue? Am I doing something wrong? Is there a potential workaround?
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
102 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I tried building the View from this section, but when there is a List on the second tab, the animation performed by the matchedGeometryEffect does not work as intended.
This video shows how the transition works with Text("Second Tab") as the second tab. Everything looks fine.
But when I replace the Text with a List, the transition flickers and does not look smooth anymore.
List {
Text("The Scarlet Letter")
Text("Moby-Dick")
Text("Little Women")
Text("Adventures of ")
}
Here is the code for the app.
import SwiftUI
@main
struct MyWatchApp: App {
@Namespace var library
@State var pageNumber = 0
private let bookIcon = "bookIcon"
var body: some Scene {
WindowGroup {
NavigationStack {
TabView(selection: $pageNumber) {
VStack {
Image(systemName: "books.vertical.fill")
.imageScale(.large)
.matchedGeometryEffect(
id: bookIcon,
in: library,
properties: .frame,
isSource: pageNumber == 0)
Text("Books")
}
.tag(0)
Text("Second Tab").tag(1)
}
.tabViewStyle(.verticalPage)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Image(systemName: "books.vertical.fill")
.matchedGeometryEffect(
id: bookIcon,
in: library,
properties: .frame,
isSource: pageNumber != 0)
}
}
}
}
}
}
I tried the example from https://developer.apple.com/documentation/swiftui/editmode. It's not working for me.
struct ContentView: View {
@Environment(\.editMode)
private var editMode
@State
private var name = "Maria Ruiz"
var body: some View {
NavigationView {
Form {
Text(String(editMode!.wrappedValue.isEditing))
if editMode?.wrappedValue.isEditing == true {
TextField("Name", text: $name)
} else {
Text("test")
}
}
.animation(nil, value: editMode?.wrappedValue)
.toolbar { // Assumes embedding this view in a NavigationView.
EditButton()
}
}
}
}
It shows the texts "false" and "test", before and after clicking Edit. What am I missing? I'm using XCode 14.0.1 and the deployment target is iOS 16. I also tried on a real iPhone and on iOS 15.5 in the Simulator. Thanks for any help.
I would like to show a nswindow at a position on screen base on height of the nswindow and its content view. I received zero width and height on macOS 15.0 and xCode 16.1 however they were returned correct width and height on previous macOS version.
import Cocoa
import SwiftUI
class AppDelegate: NSObject, NSApplicationDelegate {
private var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
window = NSWindow(
contentRect: .zero,
styleMask: [.miniaturizable, .closable, .resizable],
backing: .buffered, defer: false)
window.title = "No Storyboard Window"
window.contentView = NSHostingView(rootView: ContentView()) // a swiftui view
window.center()
let windowFrame = window.frame
print("window Frame \(windowFrame)") // print width and height zero here
window.makeKeyAndOrderFront(nil)
}
}
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}
I tried window.layoutIfNeeded() after setting contentview but it didn't work
How can I get the frame after setting contentview for nswindow on macOS 15.0?
Any one getting any issues with NavigaitonLink to seemingly innocuous views freezing when tapped on? 1 CPU at 100% memory steadily increasing until app gets killed by the system. Will freeze if any NavigationLink on the view is tapped if certain views are linked to using NavigaitonLink.
I note some people have been getting similar freezes if they use @AppStorage, but I'm not using @AppStorage. I do use CoreData tho. tho I have some views that use core data that don't freeze.
https://developer.apple.com/forums/thread/708592?page=1#736374022
has anyone experienced similar issues? or know the cause. it doesn't seem to be any of my code because if I pause the debugger it stops on system code.
I just tried the "Building a document-based app with SwiftUI" sample code for iOS 18.
https://developer.apple.com/documentation/swiftui/building-a-document-based-app-with-swiftui
I can create a document and then close it. But once I open it back up, I can't navigate back to the documents browser. It also struggles to open documents (I would tap multiple times and nothing happens). This happens on both simulator and device.
Will file a bug, but anyone know of a work-around? I can't use a document browser that is this broken.
Hello community,
I'm an iOS developer from VW group, I was doing some proof of concepts around an automaker app, and I've found a big blocker. When I was trying to summon a keyboard, it wasn't displayed.
So is it even possible?
Do I have to do some workaround with Carplay templates in order to be able to have the native keyboard from Carplay, or is there a special component that I need to introduce in my code to summon the keyboard?
Thank you very much.
David Cosialls.
It seems somewhere around the update to xcode 16 and swift 6, apple may have decided to change when view are initialized. My views suddenly pre-initialize before opening the view. Is this a new feature?
I have a regular VStack or a LazyVStack, with ForEach and navigationLinks inside. Those views that the navigation link takes you to are initializing as I am scrolling in the VStack. This is absurd, there is so much overhead going on in these views to be initialized. I can think of a fix which is to implement init functions in the onAppear, and keep a property to track if view already appeared. But before that I just want to make sure this is a new feature and not some mishap on my part, and if there is a way to disable it.
Thank you.
I'm having trouble getting the "Save to Files" option to work with ShareLink. Here's a simple example:
struct Item: Transferable {
public static var transferRepresentation: some TransferRepresentation {
FileRepresentation(exportedContentType: .jpeg) { item in
// Write a jpeg to disk
let url = URL.documentsDirectory.appending(path: "item.jpeg")
let jpegData = UIImage(named: "testImg")!.jpegData(compressionQuality: 1)!
try! jpegData.write(to: url)
return SentTransferredFile(url)
}
}
}
struct ContentView: View {
var body: some View {
ShareLink(item: Item(), preview: SharePreview("Test Item"))
}
}
The ShareSheet presents all of the usual options, but tapping "Save to Files" briefly presents an empty modal before immediately dismissing.
The following errors are logged to the console:
2022-09-12 14:19:57.481592-0700 ExportTest[3468:1374472] [NSExtension] Extension request contains input items but the extension point does not specify a set of allowed payload classes. The extension point's NSExtensionContext subclass must implement `+_allowedItemPayloadClasses`. This must return the set of allowed NSExtensionItem payload classes. In future, this request will fail with an error.
2022-09-12 14:19:58.047009-0700 ExportTest[3468:1374472] [ShareSheet] cancelled request - error: The operation couldn’t be completed. Invalid argument
Sharing finished with error: Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument" at SwiftUI/SharingActivityPickerBridge.swift:266
2022-09-12 14:19:58.584374-0700 ExportTest[3468:1379359] [AXRuntimeCommon] AX Lookup problem - errorCode:1100 error:Permission denied portName:'com.apple.iphone.axserver' PID:3472 (
0 AXRuntime 0x00000001ca77b024 _AXGetPortFromCache + 932
1 AXRuntime 0x00000001ca77d1d8 AXUIElementPerformFencedActionWithValue + 772
2 UIKit 0x00000002258b3284 3CB83860-AA42-3F9A-9B6E-2954BACE3DAC + 778884
3 libdispatch.dylib 0x0000000105078598 _dispatch_call_block_and_release + 32
4 libdispatch.dylib 0x000000010507a04c _dispatch_client_callout + 20
5 libdispatch.dylib 0x00000001050820fc _dispatch_lane_serial_drain + 988
6 libdispatch.dylib 0x0000000105082e24 _dispatch_lane_invoke + 420
7 libdispatch.dylib 0x000000010508fcac _dispatch_workloop_worker_thread + 740
8 libsystem_pthread.dylib 0x00000001ed9e8df8 _pthread_wqthread + 288
9 libsystem_pthread.dylib 0x00000001ed9e8b98 start_wqthread + 8
)
Additionally, this error is logged when the ShareSheet is first presented (before tapping Save to Files):
[ShareSheet] Couldn't load file URL for Collaboration Item Provider:<NSItemProvider: 0x282a1d650> {types = (
"public.jpeg"
)} : (null)
Has anybody had luck getting custom Transferable representations to work with ShareLink?
Hi everyone,
I need to synchronize the playback of RealityKit Timelines via SharePlay.
To do this I am trying to get the references of the timelines using "AnimationPlaybackController" and "AnimationResource". In my realitykit scene I have configured both an animation (with blender), and a timeline, the animation starts correctly when the realitykit scene starts, the timeline not.
Below the code:
struct ContentView: View {
@State private var subscriptions = [EventSubscription]()
@Environment(AppModel.self)
private var appModel
let rootEntity = Entity()
@State var testEntity: Entity?
@State var testAnimation: AnimationResource?
@State var testController: AnimationPlaybackController?
init() {
CubeComponent.registerComponent()
}
var body: some View {
RealityView { content in
content.add(rootEntity)
if let scene = try? await Entity(named: "Room", in: realityKitContentBundle) {
rootEntity.addChild(scene)
playAnimations(from: content)
}
}
.gesture(SpatialTapGesture().targetedToAnyEntity()
.onEnded({ value in
_ = value.entity.applyTapForBehaviors()
if let testEntity, let testAnimation {
testController = testEntity.playAnimation(testAnimation.repeat())
}
})
)
}
func playAnimations(from content: RealityViewContent) {
subscriptions.append(content.subscribe(to: ComponentEvents.DidAdd.self, componentType: AnimationLibraryComponent.self, { event in
let entity = event.entity
entity.components[AnimationLibraryComponent.self]?.animations.forEach({ (key, value) in
if value.definition is AnimationGroup {
if key == "/Room/TestTimeline" {
let controller = entity.playAnimation(value.repeat())
testEntity = entity
testAnimation = value
appModel.syncronizedAnimations[key] = .init(name: key, animationController: controller, entityName: entity.name)
}
} else {
if entity.name == "SphereInteractable" {
let controller = entity.playAnimation(value.repeat())
appModel.syncronizedAnimations[key] = .init(name: key, animationController: controller, entityName: entity.name)
}
}
})
}))
}
}
the variables testEntity, testAnimation and testController are for testing purposes only. If I try to start the animations in the playAnimations function, only the animation created via blender starts (the one related to the object "SphereInteractable"), the Timeline starts only if I save a reference and I play it with a tap gesture or with a delay of ! seconds with DispatchQueue.asyncAfter called in the onAppear.
is there a better way to handle this? The goal is to have a reference of the AnimationPlaybackController of the timeline, in order to sync the animation via shareplay.
Thanks
The interactiveDismissDisabled() function in SwiftUI's Sheet no longer works as expected in iOS 18.1 (22B83). It was working as expected until iOS 18.0.1. Are there any other users experiencing the same issue?
struct ContentView: View {
@State private var openSheet = false
var body: some View {
NavigationStack {
Button("Open") {
openSheet = true
}
.sheet(isPresented: $openSheet) {
SheetView()
}
}
}
}
struct SheetView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationStack {
Text("This is the Sheet")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { dismiss() }
}
}
.interactiveDismissDisabled()
}
}
}
Supplementary information: In iOS 18.1, even Apple's native Journal app allows users to swipe-to-dismiss the sheet when creating a new entry. Previously, a confirmation dialog would be displayed, but this is no longer the case.
I need a magnifying glass function for one of my SwiftUI Views, but can't find a way to implement it as needed.
I found a Youtube video where the author renders the view twice, overlaying the second over the first, then scaling and masking it to create the illusion of magnification, but this is expensive and doesn't work in many cases where more complex views are presented (e.g. a LazyVGrid).
I've also explored continually capturing partial screenshots and scaling them up to create the illusion of magnification, but there's no straightforward way to achieve this with SwiftUI without getting into the messiness of UIViewRepresentables.
Any help would be greatly appreciated
Text("Sample Text with wrong font type")
.font(.bold)
I know this code is incorrect, and it returns an error stating that .font doesn’t have a .bold type.
However, when I place this incorrect code within a stack…
…no error message appears. Instead, I get:
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
when trying to run the code. It’s unclear why the compiler doesn’t specify that the issue originates from .font(.bold). This was confusing, and I spent 20 minutes figuring out it was a typo.
I tested the life cycle of TabView and its sub-Views through the demo and found something strange. Please help analyze it. Thank you.
The demo project is here https://feedbackassistant.apple.com/feedback/15629780
Operation steps:
Step 1: launch app
Step 2: click Login button
the below log is correct
SettingsViewModel init
HomeViewModel init
HomeView appear
Step 3: click Settings tab
SettingsView appear (correct)
Step 4: click Refresh TabView button the below log is incorrect
Refresh TabView
StatusViewModel init
AccountViewModel init
StatusViewModel init (weird)
AccountViewModel init (weird)
HomeView appear (weird)
StatusViewModel deinit
AccountViewModel deinit
AccountView appear
SettingsViewModel deinit
HomeViewModel deinit
Expect log:
Refresh TabView
SettingsViewModel deinit
HomeViewModel deinit
StatusViewModel init
AccountViewModel init
AccountView appear
I want to use ShareLink+FileRepresentation to save a small text file to my iPhone with the steps below.
Tap [Share...] to display the share sheet. This sheet contains [Save to Files].
Tap [Save to Files].
A black sheet is displayed, but it disappears instantly.
In step 3, I was expecting a browser to be displayed to select the location where the file will be saved. But in fact, a black sheet appears, which quickly disappears.
The implemented code is as follows.
import SwiftUI
@main
struct SLSandboxApp: App {
var body: some Scene {
WindowGroup {
let title = Text("File Output")
let numListString = "123,456,789"
let numListFileName = "numlist.csv"
let tagListFile = TextFile(content: numListString,
filename: numListFileName)
ShareView(title: title,
fileToShare: tagListFile,
messageToPreview: numListFileName)
}
}
}
struct ShareView: View {
let title: Text
let fileToShare: TextFile
let messageToPreview: String
var body: some View {
ShareLink(item: self.fileToShare, preview: SharePreview(self.messageToPreview))
}
}
struct TextFile: Transferable {
let content: String
let filename: String
static var transferRepresentation: some TransferRepresentation {
FileRepresentation(exportedContentType: .data) {
textFile in
let data = textFile.content.data(using: .utf8) ?? Data()
let tempDirectory = FileManager.default.temporaryDirectory
let fileURL = tempDirectory.appendingPathComponent(textFile.filename)
try data.write(to: fileURL)
return SentTransferredFile(fileURL)
}
}
}
The development environment is as follows.
Xcode 15.4 (Deployment Target = iOS Deployment Target 17.5)
macOS 14.6.1
The execution environment is as follows.
iPhone SE Gen3 17.7
The following is a console log from the time the application was launched to the time when the share sheet was displayed by tapping [Share...].
Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)}>
(501) personaAttributesForPersonaType for type:0 failed with error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction.}
Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
elapsedCPUTimeForFrontBoard couldn't generate a task port
The following is the console log that was written when I tapped [Save to file] on the share sheet.
cancelled request - error: The operation couldn’t be completed. Invalid argument
What modifications should I make to the code to get the expected result?
Is there a way to structure three views vertically with a top, middle divider, and bottom view, where the…
Middle divider view “hugs” its contents vertically (grows and shrinks based on height of child views)
Top and bottom views fill the space available above and below the divider
Divider can be dragged all the way up (or down), to completely hide the top view (or bottom view)
I’ve been working on this for a while and still can’t get it quite right. The code below is close, but the parent view’s bottom edge shifts when the divider resizes. As a result, the bottom view shifts upward when the divider shrinks, whereas I want it to continue to fill the space to the bottom of the screen.
import SwiftUI
struct ContentView: View {
@State private var topRatio: CGFloat = 0.5
@State private var dividerHeight: CGFloat = 44
var body: some View {
GeometryReader { geometry in
let topInset = geometry.safeAreaInsets.top
let bottomInset = geometry.safeAreaInsets.bottom
let totalHeight = geometry.size.height
let availableHeight = max(totalHeight - bottomInset - dividerHeight, 0)
VStack(spacing: 0) {
TopView()
.frame(height: max(availableHeight * topRatio - topInset, 0))
.frame(maxWidth: .infinity)
.background(Color.red.opacity(0.3))
DividerView()
.background(GeometryReader { proxy in
Color.clear.preference(key: DividerHeightKey.self, value: proxy.size.height)
})
.onPreferenceChange(DividerHeightKey.self) { height in
dividerHeight = height
}
.gesture(
DragGesture()
.onChanged { value in
let maxDragDistance = availableHeight + dividerHeight
let translation = value.translation.height / max(maxDragDistance, 1)
let newTopRatio = topRatio + translation
topRatio = min(max(newTopRatio, 0), 1)
}
)
.zIndex(1)
BottomView()
.frame(height: max(availableHeight * (1 - topRatio), 0))
.frame(maxWidth: .infinity)
.background(Color.green.opacity(0.3))
}
}
}
}
struct DividerHeightKey: PreferenceKey {
static var defaultValue: CGFloat = 44
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
struct DividerView: View {
@State private var showExtraText = true
var body: some View {
VStack(spacing: 0) {
Text(showExtraText ? "Tap to hide 'More'" : "Tap to show 'More'")
.frame(height: 44)
if showExtraText {
Text("More")
.frame(height: 44)
}
}
.frame(maxWidth: .infinity)
.background(Color.gray)
.onTapGesture {
showExtraText.toggle()
}
}
}
struct TopView: View {
var body: some View {
VStack {
Spacer()
Text("Top")
}
.padding(0)
}
}
struct BottomView: View {
var body: some View {
VStack {
Text("Bottom")
Spacer()
}
.padding(0)
}
}
#Preview {
ContentView()
}
I'm trying to use a SwiftUI view as UICalendarView decoration and I get Call to main actor-isolated instance method 'makeContentView()' in a synchronous nonisolated context; this is an error in the Swift 6 language mode in the following code:
class Coordinator: NSObject, UICalendarViewDelegate {
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
.customView {
UIHostingConfiguration {
...
}
.makeContentView()
}
}
}
I've fixed using MainActor.assumeIsolated but is this the correct approach or is there a better one?
class Coordinator: NSObject, UICalendarViewDelegate {
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
.customView {
MainActor.assumeIsolated {
UIHostingConfiguration {
...
}
.makeContentView()
}
}
}
}
Environment
Xcode: 16.1
Swift 6 and SwiftUI for macOS development
macOS Sequoia
I have an app for macOS, and that uses an interactive widget feature.
On macOS Sequoia, the widget does not display anything and widget intent doesn't work either. I tested it on macOS Sonoma and it totally works. I assume it's a macOS bug. The app has been working fine before Sequoia.
Even on Xcode, when I tried to run the widget preview, Failed to load widget. The operation couldn't be completed. (WidgetKit_Simulator.WidgetDocument.Error error 4.).
I could avoid the error by changing version and build numbers, but I still got The operation couldn't be completed. (CHSErrorDomain error 1103.)
How am I able to fix the issue? I wanna at least know if its a bug from the app or macOS Sequoia.
I'm using Xcode 14.1 to start a Core Data project. I created a new Project, checking CoreData. The resulting program works in Preview and in the Simulator.
I've changed the data from a Item/timestamp to Locations/title. I plan to add more Attributes but that's for later.
I think I've got all the Item instances changed to Locations and timestamp to title. It seems to work OK when in Preview for ContentView.swift but crashes in the Simulator with the error
Swift/UnsafeRawBufferPointer.swift:946: Fatal error: UnsafeRawBufferPointer with negative count
Any suggestions on what I have done wrong? Thanks.
PS, the New Project includes the line Text("Select a location") but Select a location doesn't appear in the Preview.
I'm facing an issue with SwiftUI's NavigationStack when using the searchable modifier. Everything works as expected when navigating between views, but if I use the search bar to filter a list and then tap on a filtered result, I can navigate to the next view. However, in the subsequent view, my "Set and Return to Root" button, which is supposed to call popToRoot(), does not work. Here's the setup:
Structure: RootView: Contains a list with items 1-7. ActivityView: Contains a list of activities that can be filtered with the searchable modifier. SettingView: Contains a button labeled "Set and Return to Root" that calls popToRoot() to navigate back to the root view.
RootView
struct RootView: View {
@EnvironmentObject var navManager: NavigationStateManager
var body: some View {
NavigationStack(path: $navManager.selectionPath) {
List(1...7, id: \.self) { item in
Button("Element \(item)") {
// Navigate to ActivityView with an example string
navManager.selectionPath.append(NavigationTarget.activity)
}
}
.navigationTitle("Root View")
.navigationDestination(for: NavigationTarget.self) { destination in
switch destination {
case .activity:
ActivityView()
case .settings:
SettingsView()
}
}
}
}
}
ActivityView
struct ActivityView: View {
@EnvironmentObject var navManager: NavigationStateManager
let activities = ["Running", "Swimming", "Cycling", "Hiking", "Yoga", "Weightlifting", "Boxing"]
@State private var searchText = ""
var filteredActivities: [String] {
if searchText.isEmpty {
return activities
} else {
return activities.filter { $0.localizedCaseInsensitiveContains(searchText) }
}
}
var body: some View {
List {
ForEach(filteredActivities, id: \.self) { activity in
NavigationLink(
destination: SettingsView(), // Navigiere zur SettingsView
label: {
HStack {
Text(activity)
.padding()
Spacer()
}
}
)
}
}
.navigationTitle("Choose Activity")
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search Activities")
}
}
SettingView
struct SettingsView: View {
@EnvironmentObject var navManager: NavigationStateManager
var body: some View {
VStack {
Text("Settings")
.font(.largeTitle)
.padding()
Button("Set and Return to Root") {
// Pop to the root view when the button is pressed
navManager.popToRoot()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
.navigationTitle("Settings")
}
}
NavigationStateManager
// Define enum globally at the top
enum NavigationTarget {
case activity
case settings
}
class NavigationStateManager: ObservableObject {
@Published var selectionPath = NavigationPath()
func popToRoot() {
selectionPath = NavigationPath()
}
func popView() {
selectionPath.removeLast()
}
}
Problem
When I search in the ActivityView and tap on a filtered result, I successfully navigate to the SettingView. However, in this view, pressing the "Set and Return to Root" button does not trigger the navigation back to RootView, even though popToRoot() is being called.
This issue only occurs when using the search bar and filtering results. If I navigate without using the search bar, the button works as expected.
Question
Why is the popToRoot() function failing after a search operation, and how can I ensure that I can return to the root view after filtering the list?
Any insights or suggestions would be greatly appreciated!