Reputation: 143
I've been experimenting on trying to binding subclass to a SwiftUI view that takes it parent class as a parameter.
These are my classes:
class Animal {
func sound() -> String {
return ""
}
}
class Cat : Animal {
override func sound() -> String {
return "Meow"
}
func purr() {
print("purring")
}
}
class Dog : Animal {
override func sound() -> String {
return "Woof"
}
func fetch() {
print("fetching")
}
}
Here are the views I have set up.
struct ContentView: View {
@State var creature:Cat = Cat()
var body: some View {
AnimalView(creature: $creature)
}
}
struct AnimalView: View {
@Binding var creature:Animal
var body: some View {
Text(creature.sound())
.padding()
}
}
This results in the compile error:
Cannot convert value of type 'Binding<Cat>' to expected argument type 'Binding<Animal>'
What the proper way to do bind to a view the takes a parent class?
Upvotes: 0
Views: 998
Reputation: 143
Searching around I think the structure I would want is to make the view itself generic.
struct ContentView: View {
@State var creature:Cat = Cat()
@State var creature2:Dog = Dog()
var body: some View {
VStack {
AnimalView(creature: $creature)
AnimalView(creature: $creature2)
}
}
}
struct AnimalView<T:Animal> : View {
@Binding var creature:T
@State var sound:String = "No Sound"
var body: some View {
Text(creature.name)
.padding()
.onAppear {
self.sound = self.creature.sound()
}
}
}
This will allow me to bind to types that inherit from Animal and let me use one view rather that having to create a separate Cat and Dog view.
Also just in case for better form, here is a same thing with protocol and classes.
protocol Animal {
var name:String {
get
}
func sound() -> String
}
struct Cat : Animal {
var name:String {
get {
return "Cat"
}
}
func sound() -> String {
return "Meow"
}
func purr() {
print("purring")
}
}
struct Dog : Animal {
var name:String {
get {
return "Dog"
}
}
func sound() -> String {
return "Woof"
}
func fetch() {
print("fetching")
}
}
Upvotes: 2