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.