Search code examples
iosjsonswiftuiidentifiable

How do you make data in an array nested within JSON data identifiable so you can list the data?


My goal is to display some data from a JSON file in a List in SwiftUI. This is for iOS 17. I have tried a lot of different things and have done some research, but cannot find the solution.

Here's an example of the JSON data:

{
  “key1” : 123,
  “key2” : “word”,
  “key3” : [ 
      {
      “combination” : 193804,
      “color” : “blue”,
      “size” : 2
      },
      {
      “combination” : 785435,
      “color” : “red”,
      “size” : 6
      }, 
      {
      “combination” : 503953,
      “color” : “yellow”,
      “size” : 6
      } ],
   “key4” : “something”
   “key5” : {
    “key4a” : 54
    “key4b” : “thisword”
    “key4c” : “letters”
    }
}

Here are my data models:

struct ThisData: Decodable {
    let key1: Int
    let key2: String
    let key3: [OtherData]
    let key4: String
    let key5: ThatData

    struct OtherData: Decodable {
        let combination: Int
        let color: String
        let size: Int
    }

    struct ThatData: Decodable {
        let key4a: Int
        let key4b: String
        let key4c: String
    }
}

Here's the view where I'm trying to display the list. What I want to do is display, in three rows, the values for the keys "combination," "color," and "size" that are included in the array under "key3".

import SwiftUI

struct ThisView: View {
    
    @State private var thisData: [ThisData.OtherData] = []
    
    var body: some View {
    
                ScrollView {
                   
                    List(thisData) { info in
                        
                        HStack {
                            
                            Text("\(code to display variable from OtherData struct)")

                        }

                    }

                }

     }

}

At this point, I get the following error for the view:

Initializer 'init(_:rowContent:)' requires that 'CurrentConditions.CurrentData' conform to 'Identifiable'

I understand why -- there needs to be a unique identifier for the data nested under "key3." I did find a suggested solution, but it only works for a key in the "ThisData" struct/data model.

extension CurrentConditions: Identifiable {
    var id: Int { return XXX }
}

Nothing I replace XXX with works. I feel like I'm close, but I just don't have the background knowledge to figure it out. I've spent about four hours on this.


Solution

  • First of all, your models should match the json data. The simple way to do that is to copy and paste your json into https://app.quicktype.io/ it will generate most of the code for you.

    To rename or omit certain properties from decoding, use CodingKeys, for example:

     struct ThisData: Identifiable, Decodable {
         let id = UUID()  // <--- here
         let key1: Int
         let key2: String
         //...
     
     enum CodingKeys: String, CodingKey { // <--- here, no id present, so will not be decoded
         case key1
         case key2 = "created_at"  // <--- here, the json data field to decode
         // ....
     }
    
     struct OtherData: Identifiable, Decodable {
         let id = UUID()  // <--- here
         let combination: Int
         let color: String
         let size: Int
     
         enum CodingKeys: String, CodingKey { // <--- here, no id present, so will not be decoded
             case combination, color, size
         }
     }
    

    Similarly for your other models. This is a common approach to make your struct Identifiable and not decode the id.

    It is very useful to have your models with a unique id, especially those in arrays, like your OtherData

    To display the list in three rows with the data "combination," "color," and "size", use something like this:

     List(thisData) { info in
         VStack {
             Text("\(info.combination)")
             Text(info.color)
             Text("\(info.size)")
         }
     }
    

    Note, no need for ScrollView if you have a List.