class BaseSoundModel:Codable
{
var related_item : SubSoundModel = SubSoundModel()
}
class SubSoundModel:Codable
{
var parent : SoundModel? = SoundModel()
}
class SoundModel:Codable
{
var sort : String? = ""
var type : String? = ""
var name : String? = ""
var pic_file_path : String? = ""
var text : String? = ""
var related_item : SubSoundModel? = nil
}
but when I decode them I get nil parent response, what is the correct way to build equivalent class of my response?
See this recent thread which deals with a similar issue. I believe the problem here is that in SubSoundModel, the default implementation for Codable will look for a value under the key parent, but in the response you've posted the key is 6104 (which I'm assuming is some sort of entity ID that can change between responses).
As mentioned in that thread, you should probably decode to a [String: SoundModel] first, and then recreate a list of SubSoundModels from that dictionary once you have direct access to the dynamic keys.
I didn't try it, but I think all you need is changing from related_item: SubSoundModel? to related_item: SoundModel?, and use KeyedDecodingContainer.decodeIfPresent
Hi and welcome @AliJalil! Is there a particular reason you're using classes instead of structs? It also looks like some properties are always available, so in those cases you could avoid optionals:
import Foundation
struct SoundModel: Codable {
let sort: String
let type: String
let name: String
let pic_file_path: String?
let text: String
let related_item: [String: SoundModel]?
}
struct BaseSoundModel: Codable {
let related_item: SoundModel
}
let json = """
{
"related_item": {
"sort": "0",
"type": "sec_list",
"name": "sub 6104",
"pic_file_path": null,
"text": "",
"related_item": {
"13342": {
"sort": "3",
"type": "sec_list",
"name": "sub 13342",
"pic_file_path": null,
"text": "",
"related_item": {
"13343": {
"sort": "0",
"type": "sec_list",
"name": "sub 6104",
"pic_file_path": null,
"text": ""
}
}
},
"13343": {
"sort": "3",
"type": "sec_list",
"name": "sub 13343",
"pic_file_path": null,
"text": "",
"related_item": {
"13343": {
"sort": "1",
"type": "voice_list",
"name": "item 13343",
"pic_file_path": null,
"text": "text 13343"
}
}
}
}
}
}
"""
let decoder = JSONDecoder()
if let data = json.data(using: .utf8),
let base = try? decoder.decode(BaseSoundModel.self, from: data) {
dump(base)
} else {
print("Failed to decode!")
}
As others have already pointed out, the best way to handle dynamically named properties is to use dictionaries. In your attempt, the property parent cannot be found nor matched with "13342" or "13343".
@Peter-Schorn, If I had known that Codable API was reading my mind, I would not have asked, and I asked cause I didn't treat with such response before.
This is a little intemperate. There's a lot that is happening somewhat magically here, and people often struggle when the magic breaks down and they haven't ever quite grasped what it was doing before.
It doesn't look to me like the properties are really "dynamic". It looks like there's a fixed set of relationships between items, just like there's a fixed set of "sorts", and in the JSON schema's wisdom both of these are encoded as specific stringized numbers rather than specific strings of (say) text describing the relationships, which would be more readable. Regardless, I agree that the easiest thing is probably to deserialize this as a dictionary and then process it later.
Ali, I would strongly encourage you to immediately map this to a more natural-feeling static representation in Swift instead of writing a lot of code on such a dynamic representation. That probably means some sort of enum covering the different types of items, with each case knowing exactly which item data and related items it's expected to have.
I really seek for something instead of using dictionaries, but I didn't get it till now, my response represent a tree of items which are a library of sounds, each item represent a category and then sub category and sub category till leave of tree represent a sound with multiple singer and it's written words.
The number represent the parent category.