NavigationPath
A type-erased list of data representing the content of a navigation stack.
Declaration
struct NavigationPathMentioned in
Overview
You can manage the state of a NavigationStack by initializing the stack with a binding to a collection of data. The stack stores data items in the collection for each view on the stack. You also can read and write the collection to observe and alter the stack’s state.
When a stack displays views that rely on only one kind of data, you can use a standard collection, like an array, to hold the data. If you need to present different kinds of data in a single stack, use a navigation path instead. The path uses type erasure so you can manage a collection of heterogeneous elements. The path also provides the usual collection controls for adding, counting, and removing data elements.
Serialize the path
When the values you present on the navigation stack conform to the Codable protocol, you can use the path’s codable property to get a serializable representation of the path. Use that representation to save and restore the contents of the stack. For example, you can define an ObservableObject that handles serializing and deserializing the path:
class MyModelObject: ObservableObject {
@Published var path: NavigationPath
static func readSerializedData() -> Data? {
// Read data representing the path from app's persistent storage.
}
static func writeSerializedData(_ data: Data) {
// Write data representing the path to app's persistent storage.
}
init() {
if let data = Self.readSerializedData() {
do {
let representation = try JSONDecoder().decode(
NavigationPath.CodableRepresentation.self,
from: data)
self.path = NavigationPath(representation)
} catch {
self.path = NavigationPath()
}
} else {
self.path = NavigationPath()
}
}
func save() {
guard let representation = path.codable else { return }
do {
let encoder = JSONEncoder()
let data = try encoder.encode(representation)
Self.writeSerializedData(data)
} catch {
// Handle error.
}
}
}Then, using that object in your view, you can save the state of the navigation path when the Scene enters the ScenePhase.background state:
@StateObject private var pathState = MyModelObject()
@Environment(\.scenePhase) private var scenePhase
var body: some View {
NavigationStack(path: $pathState.path) {
// Add a root view here.
}
.onChange(of: scenePhase) { phase in
if phase == .background {
pathState.save()
}
}
}