I'm looking to create a protocol upon View
to group views that can be constructed from some specific data struct (MyData
)
protocol EncodableView: View {
/// Returns true if this view type can be decoded from data
static func canDecode(from data: MyData) -> Bool
/// Constructs a view from the given data
init(from data: MyData) throws
}
I want to use this protocol in a view to route to different views based on their ability to decode MyData
:
struct Example: EncodableView {
// ... implements EncodableView
}
struct ContentView: View {
private var encodableViews: [any EncodableView.Type] = [
ExampleView.self,
// ... others
]
private func navigationDestination(for data: MyData) -> some View {
for (type in encodableViews) {
// Compile complains: Type 'any EncodableView' cannot conform to 'View'
if (type.canDecode(data)) {
return type.init(from: data)
}
}
return EmptyView()
}
var body: some View {
NavigationStack {
VStack {
// ...
}
.navigationDestination(for: MyData.self) { data in
navigationDestination(for: data)
}
}
}
}
However, I'm having trouble finding the right combination of some View
, any View
, AnyView
and generics to achieve this.
I've marked the spot in my code snippet above where the compile complains: Type 'any EncodableView' cannot conform to 'View'
One Solution but not ideal because while checking the
suffix
is fast you wouldn't want to check every time the view is redrawn.Then you can use it something like
but like I mentioned above the decision will be happening multiple times, views shouldn't be deciding.
You could decide before and then tell the
View
what it is and what to show.And use it in your
navigationDestination
But you could use generics too just be concrete when you get to the
View
And in the
navigationDestination
The more decisions and processing your put on a
View
/main thread/ main actor the slower and more sluggish your app will be.