NavigationStack state restoration inconsistent

I'm trying to manage state restoration in our application. I failed to get NavigationView/NavigationLink working in pre-iOS 16 SwiftUI. I'm now trying to get it working with NavigationStack/NavigationLink/navigationDestination with iOS 16. I've built a sample application that demonstrates the issue:

import SwiftUI

@main
struct PushMultipleViews7App: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

enum Route: Hashable, Codable {
    case view1
    case view2
    case view3
    case view4
}

struct ContentView: View {

    @State
    private var navigationPath: [Route]
    @Environment(\.scenePhase)
    private var scenePhase

    init() {
        guard let data = UserDefaults
                  .standard
                  .data(
                      forKey: "NavigationPath"
                  ),
              let navigationPath = try? JSONDecoder()
                  .decode(
                      [Route].self,
                      from: data
                  )
        else {
            self._navigationPath = State(
                initialValue: []
            )
            print("Failed to read NavigationPath")
            return
        }

        print("Read:",navigationPath)
        self._navigationPath = State(
            initialValue: navigationPath
        )
    }

    var body: some View {
        VStack {
            NavigationStack(
                path: $navigationPath
            )
            {
                View1()
                    .navigationDestination(
                        for: Route.self
                    )
                { route in
                    switch route {
                    case .view1:
                        View1()
                    case .view2:
                        View2()
                    case .view3:
                        View3()
                    case .view4:
                        View4()
                    }
                }
            }
        }
            .onChange(
                of: scenePhase
            )
            { scenePhase in
                guard case .inactive = scenePhase
                else {
                    return
                }

                guard let data = try? JSONEncoder()
                          .encode(
                              navigationPath
                          )
                else {
                    print("Failed to write NavigationPath")
                    return
                }

                print("Writing:",navigationPath)
                UserDefaults
                    .standard
                    .setValue(
                        data,
                        forKey: "NavigationPath"
                    )
            }
    }

}

struct View1: View {
    var body: some View {
        VStack {
            Text("Hello View1!")
            NavigationLink(
                value: Route.view2,
                label: {
                    Text("Navigate to View2")
                }
            )
        }
            .navigationTitle("View 1")
    }
}

struct View2: View {
    var body: some View {
        VStack {
            Text("Hello View2!")
            NavigationLink(
                value: Route.view3,
                label: {
                    Text("Navigate to View3")
                }
            )
        }
            .navigationTitle("View 2")
    }
}

struct View3: View {
    var body: some View {
        VStack {
            Text("Hello View3!")
            NavigationLink(
                value: Route.view4,
                label: {
                    Text("Navigate to View4")
                }
            )
        }
            .navigationTitle("View 3")
    }
}

struct View4: View {
    var body: some View {
        Text("Hello, View4!")
    }
}```

To replicate the issue:  from Xcode 14, run the app above in your favorite iOS 16 phone simulator.  Tap on the NavigationLinks to navigate to View 4.  Navigate to the Home Screen (put the app into the background).  Wait a few seconds for UserDefaults to catch up.  "Swipe up" to kill the app.  Relaunch the app.  View4 should be displaying...which is the expected behavior.  Tap the "View 3" button (the "back" button) to display View3.  As before, navigate to the Home Screen, wait a few seconds then "swipe up" to kill the app.  Relaunch the app.  Instead of displaying "View3", the app should be displaying View1.  Evidence can be seen in the console when writing the navigation path to UserDefaults - it wrote "[]".

That's just one variation among lots of strange behavior I've seen trying to restore a NavigationStack's navigation path.

I've filed:  FB10398702

I've tried several variations of this application: using @AppStorage and @SceneStorage instead of UserDefaults.  I've also tried the sample code accompanying NavigationPath in Apple's documentation (though also based on UserDefaults).

Am I doing something incorrectly or is this a bug?

Thanks,
--David

Same problem and can reproduce with an even more basic example. Take your current NavigationPath and encode path.codable. Now take that data and decode it using NavigationPath.CodableRepresentable.self as the output type. It appears to work without an error. But as soon as I attempt to update the path within the view... path = NavigationPath(newlyDecodedCodableRepresentable) it fails with a fatal error.

Would be nice to confirm that this is a bug.

NavigationStack state restoration inconsistent
 
 
Q