diff --git a/NavigationBackportApp/Shared/ContentView.swift b/NavigationBackportApp/Shared/ContentView.swift index b45c872..01e3b28 100644 --- a/NavigationBackportApp/Shared/ContentView.swift +++ b/NavigationBackportApp/Shared/ContentView.swift @@ -14,6 +14,28 @@ struct NumberList: Hashable, Codable { let range: Range } +class ClassDestination { + let data: String + + init(data: String) { + self.data = data + } +} + +extension ClassDestination: Hashable { + static func == (lhs: ClassDestination, rhs: ClassDestination) -> Bool { + lhs.data == rhs.data + } + + func hash(into hasher: inout Hasher) { + hasher.combine(data) + } +} + +class SampleClassDestination: ClassDestination { + init() { super.init(data: "sample data") } +} + struct ContentView: View { var body: some View { TabView { diff --git a/NavigationBackportApp/Shared/NBNavigationPathView.swift b/NavigationBackportApp/Shared/NBNavigationPathView.swift index efa2bd7..df8f31f 100644 --- a/NavigationBackportApp/Shared/NBNavigationPathView.swift +++ b/NavigationBackportApp/Shared/NBNavigationPathView.swift @@ -24,6 +24,9 @@ struct NBNavigationPathView: View { .nbNavigationDestination(for: EmojiVisualisation.self, destination: { visualisation in EmojiView(visualisation: visualisation) }) + .nbNavigationDestination(for: ClassDestination.self, destination: { destination in + ClassDestinationView(destination: destination) + }) } } } @@ -56,6 +59,8 @@ private struct HomeView: View { NBNavigationLink(value: NumberList(range: 0 ..< 100), label: { Text("Pick a number") }) // Push via navigator Button("99 Red balloons", action: show99RedBalloons) + // Push child class via navigator + Button("Show ClassDestination", action: showClassDestination) // Push via Bool binding VStack { Text("Push local destination") @@ -76,6 +81,10 @@ private struct HomeView: View { $0.append(EmojiVisualisation(emoji: "🎈", count: 99)) } } + + func showClassDestination() { + navigator.push(SampleClassDestination()) + } } private struct NumberListView: View { @@ -122,3 +131,12 @@ private struct EmojiView: View { .navigationTitle("Visualise \(visualisation.count)") } } + +private struct ClassDestinationView: View { + let destination: ClassDestination + + var body: some View { + Text(destination.data) + .navigationTitle("A ClassDestination") + } +} diff --git a/NavigationBackportApp/Shared/NoBindingView.swift b/NavigationBackportApp/Shared/NoBindingView.swift index 65f15ea..c6ee3de 100644 --- a/NavigationBackportApp/Shared/NoBindingView.swift +++ b/NavigationBackportApp/Shared/NoBindingView.swift @@ -14,6 +14,9 @@ struct NoBindingView: View { .nbNavigationDestination(for: EmojiVisualisation.self, destination: { visualisation in EmojiView(visualisation: visualisation) }) + .nbNavigationDestination(for: ClassDestination.self, destination: { destination in + ClassDestinationView(destination: destination) + }) } } } @@ -28,6 +31,8 @@ private struct HomeView: View { NBNavigationLink(value: NumberList(range: 0 ..< 100), label: { Text("Pick a number") }) // Push via navigator Button("99 Red balloons", action: show99RedBalloons) + // Push child class via navigator + Button("Show ClassDestination", action: showClassDestination) // Push via Bool binding VStack { Text("Push local destination") @@ -46,6 +51,10 @@ private struct HomeView: View { $0.append(EmojiVisualisation(emoji: "🎈", count: 99)) } } + + func showClassDestination() { + navigator.push(SampleClassDestination()) + } } private struct NumberListView: View { @@ -94,3 +103,12 @@ private struct EmojiView: View { .navigationTitle("Visualise \(visualisation.count)") } } + +private struct ClassDestinationView: View { + let destination: ClassDestination + + var body: some View { + Text(destination.data) + .navigationTitle("A ClassDestination") + } +} diff --git a/Sources/NavigationBackport/DestinationBuilderHolder.swift b/Sources/NavigationBackport/DestinationBuilderHolder.swift index 01d3535..e858d09 100644 --- a/Sources/NavigationBackport/DestinationBuilderHolder.swift +++ b/Sources/NavigationBackport/DestinationBuilderHolder.swift @@ -36,18 +36,24 @@ class DestinationBuilderHolder: ObservableObject { func build(_ typedData: T) -> AnyView { let base = (typedData as? AnyHashable)?.base - let type = type(of: base ?? typedData) - let key: String if let identifier = (base ?? typedData) as? LocalDestinationID { - key = identifier.rawValue.uuidString + let key = identifier.rawValue.uuidString + if let builder = builders[key], let output = builder(typedData) { + return output + } + assertionFailure("No view builder found for type \(key)") } else { - key = Self.identifier(for: type) - } - - if let builder = builders[key], let output = builder(typedData) { - return output + var possibleMirror: Mirror? = Mirror(reflecting: base ?? typedData) + while let mirror = possibleMirror { + let key = Self.identifier(for: mirror.subjectType) + + if let builder = builders[key], let output = builder(typedData) { + return output + } + possibleMirror = mirror.superclassMirror + } + assertionFailure("No view builder found for type \(type(of: base ?? typedData))") } - assertionFailure("No view builder found for key \(key)") return AnyView(Image(systemName: "exclamationmark.triangle")) } }