Reputation: 4253
I want to create a protocol with one function for the following
@ViewBuilder
func navigate<T: View>(content: () -> T) -> some View {
switch self{
case .list:
NavigationLink(destination: Text("Test")){ content() }
default:
EmptyView()
}
}
This is my try and it doesn't work
protocol Test {
associatedtype Result: View
func navigate<T: View>(content: () -> T) -> Result
}
Upvotes: 7
Views: 2735
Reputation: 299623
This is explicitly disallowed by the Associated Type Inference section of the Opaque Result Types proposal. From the proposal:
Associated type inference can only infer an opaque result type for a non-generic requirement, because the opaque type is parameterized by the function's own generic arguments. For instance, in:
protocol P { associatedtype A: P func foo<T: P>(x: T) -> A } struct Foo: P { func foo<T: P>(x: T) -> some P { return x } }
there is no single underlying type to infer A to, because the return type of foo is allowed to change with T.
To make this more specific to your question, in order to conform to Test
, there must be exactly one type that can be assigned to Result
. However, your return type is generic, so it depends on the what is passed. The actual (non-opaque) return type of navigate
is:
_ConditionalContent<NavigationLink<T, Text>, EmptyView>
But T
is a type parameter and changes depending on how navigate
is called. So there is no one type that can be assigned to Result
.
You'll need something that can return a single, non-parameterized type. For the example you've given, that's probably AnyView, which is annoying.
That said, what you've written here doesn't really feel like a protocol. It looks a lot like just a function. I'd think a lot about how many different ways navigate
could be written. If everyone would implement it the same way, that's just a function. (If you give another example of a conforming type, it might help to design a better approach.)
Upvotes: 6
Reputation: 758
You could do this where you call it on the destination.
extension View {
func navigate< Destination: View, Label: View>(content: Label) -> some View {
NavigationLink(destination: Destination) { content. }
}
}
The problem is you can't find out the caller inside the method because you're extending a protocol.
Upvotes: 0