I've got an @Published protocol array that I am looping through with a ForEach to present the elements in some view. I'd like to be able to use SwiftUI bindable syntax with the ForEach to generate a binding for me so I can mutate each element and have it reflected in the original array.
This seems to work for the properties that are implemented in the protocol, but I am unsure how I would go about accessing properties that are unique to the protocol's conforming type. In the example code below, that would be the Animal's owner property or the Human's age property. I figured some sort of type casting might be necessary, but can't figure out how to retain the reference to the underlying array via the binding.
Let me know if you need more detail.
import SwiftUI
protocol Testable {
var id: UUID { get }
var name: String { get set }
}
struct Human: Testable {
let id: UUID
var name: String
var age: Int
}
struct Animal: Testable {
let id: UUID
var name: String
var owner: String
}
class ContentViewModel: ObservableObject {
@Published var animalsAndHumans: [Testable] = []
}
struct ContentView: View {
@StateObject var vm: ContentViewModel = ContentViewModel()
var body: some View {
VStack {
ForEach($vm.animalsAndHumans, id: \AnyTestable.id) { $object in
TextField("textfield", text: $object.name)
// if the object is an Animal, how can I get it's owner?
}
Button("Add animal") {
vm.animalsAndHumans.append(Animal(id: UUID(), name: "Mick", owner: "harry"))
}
Button("Add Human") {
vm.animalsAndHumans.append(Human(id: UUID(), name: "Ash", age: 26))
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}