-2

In a simplified example, I have these JSONs Strings

let jsonStringBird = """
{
    "identifier": "0001ABX",
    "name": "Doroty",
    "species_name": "Gorrion",
}
"""


let jsonStringPlane = """
{
    "identifier": "PL1803",
    "name": "Boing 777",
    "number_sits_in_plane": 8,
}
"""

And I have a lot of structures like these ones (they are just examples)

struct Bird: Decodable {
    var identifier: String
    var name: String
    var species: String
}

struct Plane: Decodable {
    var identifier: String
    var name: String
    var sits: String
}

So, I want to decode my structs without modify them (avoid overriding the init from decoder method and avoid having a private CodingKeys enum).

Maybe having a global CodingKey enum/struct like this one, but I don't know how to tell to the JSONDecoder to use the following CodingKey for all my structs (I only know how to do it in the init from decoder method)

enum MyCodingKeys: String, CodingKey {
    case identifier
    case name
    case species = "species_name"
    case sits = "number_sits_in_plane"
}

My point is that I have a lot of those structures, and I would prefer to keep them as simple as posible

Notes

In my real project I'm actually using CBORCoding where I'm mapping [Int, AnyCodable] properties, not [String, AnyCodable].

So, for the question here is important to use JSONDecoder and use CodingKeys. That way I could translate it to CBORCoding

Gerardo
  • 168
  • 2
  • 8
  • Thank you @JoakimDanielson. However, in my real project I'm mapping [Int, AnyCodable] properties, not [String, AnyCodable]. So, the enum CodingKeys is mandatory. I just wrote it in this way to simplify my question sorry – Gerardo Jul 13 '23 at 15:58
  • try to make it clearer what part of your question is a fixed specification and what is variable in design. Then edit your question accordingly. – soundflix Jul 13 '23 at 16:51
  • 1
    There is no such thing as a global CodingKey enum, the question is changing all the time but as I see it you need to implement a CodingKey enum for each type that requires it. – Joakim Danielson Jul 13 '23 at 19:00

1 Answers1

0

Here's an approach with JSONSerialization that works with your example.

+ it does not need any CodingKey.

+ it is totally flexible with what and how many attributes your object will have.

- all attributes are stored in a dictionary with the values of type Any.

- only one object type.

struct myObject {
    let identifier: String
    let name: String
    let attributes: [String: Any]
}

func myObjectFromJSON(_ jsonString: String) -> myObject? {
    let data = Data(jsonString.utf8)
    
    if var json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
        print(type(of: json), json) // Dictionary<String, Any> ["species_name": Gorrion, "identifier": 0001ABX, "name": Doroty]
        
        if let identifier = json["identifier"] as? String, let name = json["name"] as? String {
            json.removeValue(forKey: "identifier")
            json.removeValue(forKey: "name")
            let newObject = myObject(identifier: identifier, name: name, attributes: json)
            return newObject
        }
    }
    return nil
}

Usage:

let object1 = myObjectFromJSON(jsonStringBird)
let object2 = myObjectFromJSON(jsonStringPlane)
soundflix
  • 928
  • 9
  • 22
  • Thank you. In my real project I'm mapping [Int, AnyCodable] properties using CBORDecoder, similar how JSONDecoder does. So, the enum CodingKeys is mandatory. I will update my question with more details – Gerardo Jul 13 '23 at 18:17