0

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?

4
  • 1
    Can the params' values really be Any? E.g. Can I pass a UIViewController as a param value? You'll most likely want to constrain it to a narrower set of JSON-supported (or Encodable) types Commented Jul 11, 2023 at 15:00
  • Probably just strings, ints, and floats. Commented Jul 11, 2023 at 15:07
  • 1
    Was there a problem with the JSON type I discussed on the last question? stackoverflow.com/questions/65901928/… For a version with basically this exact syntax, see github.com/rnapier/RNAJSON/tree/main/Sources/JSONValue Commented Jul 11, 2023 at 15:21
  • @RobNapier I don't quite follow that answer. How would my Event struct need to change to accommodate that? Could you post an answer here? Commented Jul 11, 2023 at 15:37

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Appreciate it. Going to go with JSONSerialization for brevity here, but this is good to know.
0

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).

2 Comments

thanks. Events isn't an array though. I'm just POSTing one event at a time.
Still easier. Please see the edit

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.