Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI nested Navigation

When I navigate, the next page opens and closes quickly. Why ?

enter image description here

I tried this on an empty project and didn't run into this issue. Why in my project does the navigation come back after going forward? I want to create a nested navigation structure.

MY PROJECT CODES:

App:

@main
struct FileApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear {
                    UserDefaults.standard.set(false, forKey: "_UIConstraintBasedLayoutLogUnsatisfiable")
                }
        }
    }
}

ContentView:

struct ContentView: View {
    @StateObject var safeFileVM: SafeFileViewModel = SafeFileViewModel()
    var body: some View {
        NavigationView {
            AView(safeFileVM: safeFileVM)
        }
    }
}

AView:

struct AView: View {
    @ObservedObject var safeFileVM: SafeFileViewModel
    
    @State var currentLocation = ""
    @State var currentFolder: String = "Safe File"
    var body: some View {
        List(safeFileVM.arrayOfFiles, id: \.id) { folderItem in
            BView(safeFileVM: safeFileVM, currentFile: folderItem, currentLocation: currentLocation)
        }
        .navigationTitle(Text(currentFolder))
        .onAppear {
            safeFileVM.additionPath = currentLocation
            safeFileVM.takeArrayOfItems()
        }
    }
} 

BView:

struct BView: View {
    @ObservedObject var safeFileVM: SafeFileViewModel
    @State var currentFile: MyFile
    @State var currentLocation: String
    var body: some View {
        VStack {
            if currentFile.typeOfFile == "folder" {
                NavigationLink(currentFile.fileName) {
                    AView(safeFileVM: safeFileVM, currentLocation: currentLocation + "/" + currentFile.fileName, currentFolder: currentFile.fileName)
                }
                .isDetailLink(false)
            } else {
                Text(currentFile.fileName)
            }
        }
    }
}

EMPTY PROJECT CODES:

ContentView:

struct ContentView: View {
    var body: some View {
        NavigationView {
            AView()
                .navigationBarTitleDisplayMode(.inline)
        }
    }
}

AView:

struct AView: View {
    var body: some View {
        List(0..<5) { item in
            BView(title: item)
        }
    }
}

BView:

struct BView: View {
    var title: Int = 0
    var body: some View {
        NavigationLink("test \(title)") {
            AView()
        }
    }
}
like image 235
Ufuk Köşker Avatar asked Apr 07 '26 23:04

Ufuk Köşker


1 Answers

In your AView's onAppear, you call takeArrayOfItems which, I presume, mutates the .arrayOfFiles property in the view model.

In your hierarchy, your top level AView creates a list of items which link to BViews, and the folder links in BView link to AView again.

When that nested AView is called, onAppear is called again - so takeArrayOfItems is probably mutating the root layer of folders, which invalidates the links further down the path; and so the navigation view resets itself back to the root.

You should probably take care to ensure that any refreshing of your hierarchy doesn't invalidate the data driving your UI. It might also be useful to watch Demystifying SwiftUI from WWDC21 which goes into, among other things, how SwiftUI uses object identity to work out when the interface needs to be redrawn.

And if your app can be iOS16 only, you'll also have access to the new navigation UI components in SwiftUI, which provide for stacks to be driven by an array of state objects, making it much easier to maintain stack position when data is changing underneath. A useful video on this topic is The SwiftUI cookbook for navigation from WWDC22.

like image 183
Scott Matthewman Avatar answered Apr 10 '26 14:04

Scott Matthewman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!