skip to Main Content

Say I have to send this data to the server:

struct Event: Codable {
    let title: String
    let params: [String:Any]? //Not allowed
}

So for instance, these events could look like any of these:

let event = Event(title: "cat was pet", params:["age": 7.2])
let event = Event(title: "cat purred", params:["time": 9])
let event = Event(title: "cat drank", params:["water": "salty", "amount": 3.3])

I need the ability to send any arbitrary amount of key/value pairs as params to the event. Is this even possible with Codable? If not, how would I encode params as a json string?

2

Answers


  1. Using a type like JSONValue, it would look almost identical to what you describe:

    import JSONValue
    
    struct Event: Codable {
        let title: String
        let params: JSONValue?  // JSONValue rather than [String: Any]
    }
    
    // All the rest is the same
    let event1 = Event(title: "cat was pet", params:["age": 7.2])
    let event2 = Event(title: "cat purred", params:["time": 9])
    let event3 = Event(title: "cat drank", params:["water": "salty", "amount": 3.3])
    

    There’s a lot of helper code in JSONValue, but at its heart is just an enum, as described in Swift/JSONEncoder: Encoding class containing a nested raw JSON object literal:

    public enum JSONValue {
        case string(String)
        case number(digits: String)
        case bool(Bool)
        case object([String: JSONValue])
        case array([JSONValue])
        case null
    }
    

    Everything else is just helpers to encode/decode, conform to ExpressibleBy... protocols, etc.

    Login or Signup to reply.
  2. Codable is magic if all types conform to Codable, but in your case I suggest traditional JSONSerialization. Add a computed property dictionaryRepresentation

    struct Event: {
        let title: String
        let params: [String:Any]
    
        var dictionaryRepresentation: [String:Any] {
            return ["title":title,"params":params] 
        }
    }
    

    then encode the event

    let data = try JSONSerialization.data(withJSONObject: event.dictionaryRepresentation)
    

    This is less expensive/cumbersome than forcing Any to become Codable (no offense, Rob).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search