Is it possible to have 2 structs/arrays
in the same ForEach
(for the Option 3)? If so, how? All my attempts were unsuccessful.
import Foundation
import SwiftUI
struct Car: Vehicle, Identifiable {
let id = UUID()
let name: String
}
struct Bike: Vehicle, Identifiable {
let id = UUID()
let name: String
}
let cars = [Car(name: "Renault"), Car(name: "Peugeot")]
let bikes = [Bike(name: "Yamaha"), Bike(name: "Honda")]
protocol Vehicle {
var name: String { get }
}
struct ParentView: View {
var body: some View {
// Option 1 OK
ForEach(cars.sorted { $0.name < $1.name }) { car in
ChildView(vehicle: car)
}
// Option 2 OK
ForEach(bikes.sorted { $0.name < $1.name }) { bike in
ChildView(vehicle: bike)
}
// Option 3 NOT OK
ForEach((cars, bikes).sorted { $0.name < $1.name }) { vehicle in
ChildView(vehicle: vehicle)
}
}
}
struct ChildView: View {
let vehicle: Vehicle
var body: some View {
Text(vehicle.name)
}
}
Thanks, in advance!
Here is an alternative solution for the case when you don't want to or simply cannot change a protocol just to adhere to some UI requirements.
We want to use any type that conforms to Vehicle
and yet be able to efficiently use List/ForEach by also conforming to Identifiable
. For this solution we can create a wrapper type for this
struct VehicleUI: Identifiable {
let id = UUID()
let vehicle: any Vehicle
}
And then we can map and join the types directly in the view or some model class
(cars + bikes)
.map(VehicleUI.init)
.sorted(using: KeyPathComparator(\.vehicle.name, order: .forward))
Example:
struct ParentView: View {
var vehicles: [VehicleUI] {
(cars + bikes)
.map(VehicleUI.init)
.sorted(using: KeyPathComparator(\.vehicle.name, order: .forward))
}
var body: some View {
List {
ForEach(vehicles) { vehicle in
ChildView(vehicle: vehicle.vehicle)
}
}
}
}