I'm a Swift/SwiftUI beginner and am trying to make a program that visualizes a few different types of data (w/ swift 5.7, targeting macOS).
I have a root "Data" protocol, and a few different protocols for its subtypes. A simplified example:
protocol Data {}
protocol HasA: Data { var a: String {get} }
protocol HasB: Data { var b: String {get} }
struct StructA: HasA { let a: String = "I am A"}
struct StructB: HasB { let b: String = "I am B"}
Now, I'd like to have a view that picks a visualization strategy based on the specific type of data it receives. This doesn't work, but here's how I'd write in a dynamic language:
struct DataView: View {
let data: Data
var body: some View {
// this doesn't actually work
if data is HasA {
ViewA(data) // ERROR: type 'any Data' does not conform to the expected type 'HasA'
} else if data is {
ViewDefault(data)
}
}
}
I've tried many, many different ways to accomplish this, without success. So clearly, there's something fundamentally wrong with my strategy. How should I be approaching this problem? Generics? Using concrete classes only? More existential types?
Some things I've tried that didn't work
Generics in many different forms, all of which ended up with
type 'any Data' does not conform to expected type 'Data'errors.Protocol extensions of the form:
extension Data { func getView() -> View { ...} } extension HasA { func getView() -> View { ...} }This will compile, but at runtime, it only calls the
Data.getView()implementation, not theHasA.getView()implementation.Adding a required
func getView() -> any Viewmethod to theDataprotocol, and then implementing it on the concrete classes. This leads toType 'any View' cannot conform to 'View'errors.Runtime dispatch via protocol conformance - this is what's in the example above, i.e.,
if data is HasA {return ViewA(data)}. I didn't really expect this to work, and it doesn't - the compiler complains about protocol conformance.
Edited to add
In addition to @EDUsta's solution below, in my real production solution, I also had to remove all associated types and generic parameters from the data protocols that the view layer uses - otherwise downcasting wouldn't work.