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)
            }
        }
    }
}