I have a Swift struct that looks like this:
struct MyStruct: Codable {
var id: String
var name: String
var createdDate: Date
}
To that, I would like to add another property: a [String:Any] dictionary. The result would look like this:
struct MyStruct: Codable {
var id: String
var name: String
var createdDate: Date
var attributes: [String:Any] = [:]
}
In the end, I would like to be able to serialize my MyStruct instance to a JSON string, and vice versa. However, when I go to build I get an error saying,
Type 'MyStruct' does not conform to protocol 'Codable'
Type 'MyStruct' does not conform to protocol 'Decodable'
It's clearly the attributes var that is tripping up my build, but I'm not sure how I can get the desired results. Any idea how I can code my struct to support this?
Since the comments already point out that
Anytype has nothing to do with generics, let me jump straight into the solution.First thing you need is some kind of wrapper type for your Any attribute values. Enums with associated values are great for that job. Since you know best what types are to be expected as an attribute, feel free to add/remove any case from my sample implementation.
We will be later wrapping attribute values from the
[String: Any]dictionary into the wrapper enum cases, but first we need to make the type conform to theCodableprotocols. I am usingsingleValueContainer()for the decoding/encoding so the final json will produce a regular json dicts.At this point we are good to go, but before we will decode/encode the attributes, we can use some extra interoperability between
[String: Any]and[String: MyAttrubuteValue]types. To map easily betweenAnyandMyAttrubuteValuelets add the following:Now, with the quick
valueaccess and newinit, we can map values easily. We are also making sure that the helper properties are only available for the dictionaries of concrete types, the ones we are working with.Now the final part, a custom
Codableimplementation forMyStructThis solution is fairly long, but pretty straight-forward at the same time. We lose automatic
Codableimplementation, but we got exactly what we wanted. Now you are able to encode ~Any~ type that already conforms toCodableeasily, by adding an extra case to your newMyAttrubuteValueenum. One final thing to say is that we use similar approach to this one in production, and we have been happy so far.That's a lot of code, here is a gist.