Issue #446
Suppose we have Service protocol, and want to use in List
1 2 3
| protocol Service { var name: String { get } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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
1 2 3 4 5 6 7
| var body: some View { if useImage { return AnyView(Image("my image")) } else { return AnyView(Text("my text")) } }
|
Make AnyService conform to Identifiable
1 2 3 4 5 6 7 8 9
| 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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) } } } }
|