-2

I have a json that I decode using Codable.

struct Item: Codable {
    let data: Data // dictionary or array
}

struct Data: Codable {
    let id: Int
}

The "data" field can be an array or a dictionary.

How do I decode my json ?

example json

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • 1
    @Olympiloutre You are wrong, this format is actually quite common and `Any` can be avoided. – Sulthan Sep 25 '21 at 21:26
  • @Sulthan totally right I was working on it right now. Didn't see the "type" associated I thought it was just random datas that could either be an array or a dict. My bad ! – Olympiloutre Sep 25 '21 at 21:27
  • How would the `id` be extracted in both cases? I assume for dictionary is pretty obvious, but what about the array? – Cristik Sep 26 '21 at 10:02

1 Answers1

2

You have to decode data depending on type. That means you have to first decode type and then continue depending on its value. Usually to store such items we would use an enum with associated values:

enum Item: Decodable {
    case onboarding(OnboardingData)
    case entry(EntryData)

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let type = try container.decode(String.self, forKey: .type)

        switch type {
        case "onboarding":
            let data = try container.decode(OnboardingData.self, forKey: .data)
            self = .onboarding(data)
        case "entry":
            let data = try container.decode(EntryData.self, forKey: .data)
            self = .entry(data)
        default:
            throw DecodingError.unknownType
        }
    }

    private enum CodingKeys: String, CodingKey {
        case type
        case data
    }

    private enum DecodingError: String, Error {
        case unknownType
    }
}

struct OnboardingData: Decodable {
}

struct EntryData: Decodable {
}

OnboardingData and EntryData are just type placeholders. You can change them to anything to want, e.g. an array of items. Also, you might wrap arrays inside them.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • The "type" field has many values. Not only "onboarding" and "entry" – Игорь Сазонов Sep 25 '21 at 21:30
  • This solution is not suitable for this json. Since all the values of the type field are not known – Игорь Сазонов Sep 25 '21 at 21:36
  • @ИгорьСазонов What exactly is not suitable? Do you want to only parse the values you know and skip the others? – Sulthan Sep 25 '21 at 21:44
  • No. I want to parse all the values. But I don't know all the values of the "type" field. – Игорь Сазонов Sep 25 '21 at 21:52
  • @ИгорьСазонов The `type` fields are part of the JSON format. You cannot parse JSON if you don't know the format. – Sulthan Sep 25 '21 at 21:57
  • @Sulthan that's what I thought yesterday (guess the question was edited). It's achievable if he knows what's in the array or dictionnary (e.g. its either an array of `[Type]` or a dictionnary of `[String:Type]` idk), by try catching to decode it as an array, then falling into decoding it as a dictionnary... See now why I was so categorical haha – Olympiloutre Sep 26 '21 at 13:23