Issue #446
Suppose we have Service protocol, and want to use in List
protocol Service {
var name: String { get }
}
struct MainView: View {
let services = [
Car()
Plane()
]
var body: some View {
List(services) { service in
HStack {
Image(service.name)
Text(service.name)
}
}
}
}
This is not possible because item in List needs to conform to Identifiable
Protocol type ‘Service’ cannot conform to ‘Identifiable’ because only concrete types can conform to protocols
Type eraser
In the same way that SwiftUI uses type eraser, for example AnyView
, we can introduce AnyService
to work around this
var body: some View {
if useImage {
return AnyView(Image("my image"))
} else {
return AnyView(Text("my text"))
}
}
Make AnyService conform to Identifiable
struct AnyService: Identifiable {
let id: String
let service: Service
init(_ service: Service) {
self.service = service
self.id = service.name
}
}
Then in our View, we just need to declare services wrapped inside AnyService
struct MainView: View {
let services = [
AnyService(Car()),
AnyService(Plane())
]
var body: some View {
List(services) { anyService in
HStack {
Image(anyService.service.name)
Text(anyService.service.name)
}
}
}
}
A bit refactoring, we can just declare normal services and map them
struct MainView: View {
let services: [Service] = [
Car(),
Plane()
]
var body: some View {
List(services.map({ AnyService($0 })) { anyService in
HStack {
Image(anyService.service.name)
Text(anyService.service.name)
}
}
}
}