Reputation: 229
I have a protocol for an object as such:
public protocol Viewable {
associatedtype Content: View
var parent: (any Viewable)? { get }
var body: Content { get }
}
What I would like is to show the body of the view inside of another view, something like this:
public struct SampleView: View {
var object: (any Viewable)?
public var body: some View {
object!.body
}
}
But I am getting an error Type 'any View' cannot conform to 'View'
What would be the best way to show a view of an object which was defined in a protocol extension without using AnyView?
Thanks.
Upvotes: 2
Views: 816
Reputation: 7668
Your object
cannot be an existential type (a dynamically typed protocol) because the protocol requirements for View
specify the View.Body
is a generic, associated type.
We need to retain the full, generic type information in order to satisfy the some View
requirement for body
on View
.
The answer is to use a concrete generic type:
public struct SampleView: View {
var object: (some Viewable)?
public var body: some View {
object!.body
}
}
For clarity, this can be spelled more traditionally to make it clear this is a generically constrained type to your custom protocol:
public struct SampleView<T: Viewable>: View {
var object: T?
public var body: some View {
object!.body
}
}
This behaviour is detailed more in the proposal for SE-0309 which originally allowed existential types to be used for any protocol type.
To still use Viewable
types heterogeneously (such as in an Array), you'll need to create an additional layer of abstraction, such as creating an enum
with concrete values as associated values.
struct SampleView: Viewable { ... }
struct ProfileView: Viewable { ... }
struct PreferencesView: Viewable { ... }
enum Views {
case sample(SampleView)
case profile(ProfileView)
case preferences(PreferencesView)
}
var views = [Views]()
Now you can access the concrete types in the associated values.
Obviously this solution does not scale as well though, and this kind of approach to dealing with generic types should be used in limited circumstances to avoid this enum
becoming very large with many cases.
Upvotes: 2