ForEach Loop from Local JSON

Hi team, I am trying to build an app for my friends business and I have hit a stumbling block where I can’t seem to capture an element of the local JSON data when using the ForEach loop. Would somebody be able to take a look at where I’m going wrong please? Should I add my code through this forum or provide a GitHub link?
Thanks, Adam

Hi Adam,

Welcome to the code crew community.

You can either post the code to say, DropBox or Google Drive and then post a share link in a reply or if you prefer, push it to GitHub (making sure that it is a public repo) and then advise the link.

Before you do that, just check that your JSON code matches your Model (struct or class) to ensure that it is being decoded successfully.

Hi Chris, thanks.

GitHub link is https://github.com/Adam-Woods-xCode/CourtierV2.git

I’m new to coding so I’m sure it’s an obvious error.

When I delete the ForEach and amend the Text to “EnterName”, it displays a single row as planned.

Thanks again

Where is this occurring in your project? You’ve posted the entire project but didn’t narrow down where the issue is.

Hi,
It’s in the SingerView.
Thanks

Three issues:

  1. Your JSON has an extraneous outer array and so it doesn’t correspond to the data structure you are using for Decodable. Remove the [ ] surrounding your JSON.

  2. The keys for your three objects in your JSON (Singers, Bands, Instrumentalists) don’t correspond to the keys in your Decodable data structure (singers, bands, instrumentalists). You either need to adjust the capitalization so they match or use a CodingKeys enum to supply correspondences.

Like this:

class Courtier: Identifiable, Decodable {
    
    var id: UUID?
    var singers: [Singers]
    var bands: [Bands]
    var instrumentalists: [Instrumentalists]
    
    enum CodingKeys: String, CodingKey {
        case id
        case singers = "Singers"
        case bands = "Bands"
        case instrumentalists = "Instrumentalists"
    }
}
  1. In SingerService.getLocalData() you are trying to decode an array of Singer objects:
do {
    
    let singerData = try decoder.decode([Singers].self, from: data)
    
    for s in singerData {
        s.id = UUID()
    }
    
    return singerData
}

but the JSON you supply is actually a Courtier type that contains an array of Singers. So you need to change that code to:

do {
    
    let courtier = try decoder.decode(Courtier.self, from: data)
    
    for s in courtier.singers {
        s.id = UUID()
    }
    
    return courtier.singers
}
1 Like

And a suggestion:

Rename your data structures. You have Singers, Bands and Instrumentalists but each of those represents one item. So they should be Singer, Band and Instrumentalist.

That makes your Courtier class read nicer:

class Courtier: Identifiable, Decodable {
    
    var id: UUID?
    var singers: [Singer]
    var bands: [Band]
    var instrumentalists: [Instrumentalist]
}

So singers is an array of multiple Singer objects, not an array of multiple Singers objects, etc.

1 Like

Thank you so much, really appreciate this.