4

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()
        }
    }
}
Ufuk Köşker
  • 1,288
  • 8
  • 29
  • This was never worked with NavigationView, because each screen has own stack of links, that's why forget about NavigationView and go forward with data-driven NavigationStack – Asperi Jun 07 '22 at 17:27
  • change @State var currentFile: MyFile to let currentFile: MyFile – malhal Jun 07 '22 at 23:39
  • although you should not use this infinite recursion of `AView` referring to `BView`, and `BView` referring to `AView`. Your "EMPTY PROJECT CODES:" surprisingly worked for me on ios 15.5. On macos 12.5, Xcode 14, target ios-15.5. – workingdog support Ukraine Jun 08 '22 at 07:39
  • your "MY PROJECT CODES:" does not compile, and so cannot be tested, it is missing some parts, such as `SafeFileViewModel` and `MyFile`. Show code that can reproduce your issue. – workingdog support Ukraine Jun 08 '22 at 11:32

1 Answers1

1

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.

ScottM
  • 7,108
  • 1
  • 25
  • 42
  • That's a great explanation, and it helped me a lot figuring out what was going wrong with my navigation. Thank you! – VoodooBoot Jul 14 '23 at 17:52