2

An example of the response from the server is below.

The list consists of elements that have heterogeneous substructures in the info fields. Each of them contains 3 fields with the same types, but they have different keys.

I don't know how to decode this, I haven't encountered such a problem so far. I can't find an example on the Internet that fits this case.

I wanted to decode the enum type at the beginning and select the appropriate info structure based on it, but it doesn't work.

{
  "data":[
    {
      "type":"league",
      "info":{
        "name":"NBA",
        "sport":"Basketball",
        "website":"https://nba.com/"
      }
    },
    {
      "type":"player",
      "info":{
        "name":"Kawhi Leonard",
        "position":"Small Forward",
        "picture":"https://i.ibb.co/b5sGk6L/40a233a203be2a30e6d50501a73d3a0a8ccc131fv2-128.jpg"
      }
    },
    {
      "type":"team",
      "info":{
        "name":"Los Angeles Clippers",
        "state":"California",
        "logo":"https://logos-download.com/wp-content/uploads/2016/04/LA_Clippers_logo_logotype_emblem.png"
      }
    }
  ]
}
4
  • 1
    I recommend an enum with associated types like described here Commented Apr 22, 2021 at 16:16
  • Are you able to know what are all possible keys? If yes, then you can declare all of them as optionals. Commented Apr 22, 2021 at 16:45
  • @AhmadF I know all the types, but declaring all the fields as optionals is not an option - the codebase would grow too fast. Commented Apr 22, 2021 at 17:04
  • @vadian, I followed your advice and the following code snippet was created: pastebin.com/S3uSXgtU Didn't the 2 enums make a mess? Commented Apr 22, 2021 at 17:05

1 Answer 1

2

Your code on pastebin is too complicated, I mean this

let jsonString = """
{
  "data":[
    {
      "type":"league",
      "info":{
        "name":"NBA",
        "sport":"Basketball",
        "website":"https://nba.com/"
      }
    },
    {
      "type":"player",
      "info":{
        "name":"Kawhi Leonard",
        "position":"Small Forward",
        "picture":"https://i.ibb.co/b5sGk6L/40a233a203be2a30e6d50501a73d3a0a8ccc131fv2-128.jpg"
      }
    },
    {
      "type":"team",
      "info":{
        "name":"Los Angeles Clippers",
        "state":"California",
        "logo":"https://logos-download.com/wp-content/uploads/2016/04/LA_Clippers_logo_logotype_emblem.png"
      }
    }
  ]
}
"""

struct Response: Decodable {
    let data: [Datum]
}

struct League: Codable {
    let name: String
    let sport: String
    let website: URL
}

struct Player: Codable {
    let name: String
    let position: String
    let picture: URL
}

struct Team: Codable {
    let name: String
    let state: String
    let logo: URL
}

enum Datum: Decodable {
    case league(League)
    case player(Player)
    case team(Team)
    
    enum DatumType: String, Decodable {
        case league
        case player
        case team
    }
    
    private enum CodingKeys : String, CodingKey { case type, info }
 
    init(from decoder : Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let type = try container.decode(DatumType.self, forKey: .type)
        switch type {
        case .league:
            let item = try container.decode(League.self, forKey: .info)
            self = .league(item)
        case .player:
            let item = try container.decode(Player.self, forKey: .info)
            self = .player(item)
        case .team:
            let item = try container.decode(Team.self, forKey: .info)
            self = .team(item)
        }
    }
}

do {
    let response = try JSONDecoder().decode(Response.self, from: Data(jsonString.utf8))
    let data = response.data
    print(data)
//    receivedData.forEach { (datum) in
//        let cell = Cell()
//        cell.configure(with: datum.info.rowData)
//        cells.append(cell)
//    }
//    cells.forEach({ print($0.title, $0.subtitle) })
} catch {
    print(error)
}

In the cell switch on the type

switch datum {
    case .league(let league): // so something with league
    case .player(let player): // so something with player
    case .team(let team): // so something with team
} 
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, @vadian! Could you please tell me how to put these datum nested values inside a following structure snippet? pastebin.com/Lc1u3aQ2 I want to have a list of Items where Item<Displayable>, but I am afraid this is not possible, because only struct/enum/class types can conform to protocols.
An answer depends on the context the structs are used in. Please ask a new question and provide more information. And please add relevant code directly to the question as text rather than as external link.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.