Home > Net >  SwiftUI: Using ForEach to dynamically generate a List of array data within an array
SwiftUI: Using ForEach to dynamically generate a List of array data within an array

Time:11-11

Following the apple tutorial "Scrumdinger" app (DesiredEndState

The trouble I'm having is constructing my CardView to properly pull data from the Fleet Model. Once I get the CardView ironed out, everything else should populate appropriately.

Here is my latest attempt at a CardView (with errors):

error2

struct RateCardView: View {
var fleet: Fleet

var body: some View {
    ForEach(fleet.rates) { rate in
        HStack {
            Text("Year \(rate.year)")
            Spacer()
            Text("\(rate.foHourlyRate)")
            Spacer()
            Text("\(rate.captHourlyRate)")
        }
    }
}
}

Here is my Model data... it has an Array within an Array, which is where this diverges from the apple Scrumdinger tutorial:

struct Fleet: Identifiable {
let id: UUID
var fleetName: String
var rates: [HourlyRates]

init(id: UUID = UUID(), fleetName: String, rates: [HourlyRates]) {
    self.id = id
    self.fleetName = fleetName
    self.rates = rates
}
}
extension Fleet {
static let fleetList: [Fleet] = [
 Fleet(fleetName: "B717", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "B737-7/8", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "B737-9", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "B757", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "B767-4", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "A220", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "A319/320", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "A321", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "A330", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])]),
 Fleet(fleetName: "A350", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])])
]
}
struct HourlyRates: Identifiable {
let id: UUID
var year: [Int]
var foHourlyRate: [Double]
var captHourlyRate: [Double]

init(id: UUID = UUID(), year: [Int], foHourlyRate: [Double], captHourlyRate: [Double]) {
    self.id = id
    self.year = year
    self.foHourlyRate = foHourlyRate
    self.captHourlyRate = captHourlyRate
}
}

My parent "PayRateView" should navigate to multiple child "RateDetailView"s for each fleet type:

struct PayRateView: View {
var fleet: [Fleet]

var body: some View {
    NavigationView {
        List {
            ForEach(fleet, id: \.fleetName) { plane in
                NavigationLink(destination: RateDetailView(fleet: fleet)) {
                    Text(plane.fleetName)
                }
            }
        }
        .navigationTitle("Delta Fleet Pay Rates")
    }
}
}

Here is my PayRateDetailView:

struct RateDetailView: View {
var fleet: [Fleet]

var body: some View {
    List {
        ForEach (fleet, id: \.fleetName) { line in
            RateCardView(fleet: fleet)
        }
    }
}
}

UPDATE:

error2

CodePudding user response:

The way that you are trying to access the hourly rates in your Fleet model is the problem. You can access properties using dot-notation.

To retrieve the list of hourly rates (so the [HourlyRates]) for a fleet, use fleet.rates. This will be an array of rates, and for each rate, you want to display an HStack displaying the year, foHourlyRate, and captHourlyRate.

Also take into account the difference between fleet = [Fleet] and fleet = Fleet. The former is an array of fleets, meaning fleet.rates would be a compile error (an array does not have a property called rates). The latter is a single Fleet object, which has, as you have defined, a property rates that can be accessed. This property contains an array of HourlyRates (i.e. [HourlyRates]) which can then be looped over using ForEach.

struct RateCardView: View {
    var fleet: Fleet // You are displaying a single fleet's rates, so don't use [Fleet]

    var body: some View {
        // ForEach will loop over an array (in this case the array of `HourlyRate`s) and produce a view for each element.
        ForEach(fleet.rates) { rate in
            HStack {
                Text("Year \(rate.year)"
                Spacer()
                Text("\(rate.foHourlyRate)")
                Spacer()
                Text("\(rate.captHourlyRate)")
            }
        }
    }
}

Regarding the HourlyRates object

As it stands, you're creating each Fleet with a single HourlyRates object that contains arrays of Ints and Doubles, whereas you want (I assume) an array of HourlyRates with each a single Int, Double, etc. for their property. See below.

static let fleetList: [Fleet] = [
    Fleet(fleetName: "B717", rates: [HourlyRates(year: [1,2,3,4,5,6,7,8,9,10,11,12], foHourlyRate: [91,126,148,152,155,159,163,167,169,171,173,174], captHourlyRate: [0,235,236,238,240,242,244,246,248,250,252,254,256])])

    // Should be:
    Fleet(fleetName: "B717", rates: [
        HourlyRate(year: 1, foHourlyRate: 91, captHourlyRate: 0),
        HourlyRate(year: 2, foHourlyRate: 126, captHourlyRate: 235),
        HourlyRate(year: 3, foHourlyRate: 148, captHourlyRate: 236),
        // ...
    ]
}
  • Related