I'm looking to store models objects in a Dictionary and would like to serialize the whole dictionary using JSONEncoder
into data and subsequently into a string and save it.
The idea is to use Swift 4's out of the box Encodable
to ensure anything that I add to the dictionary will be serialized which can include primitives and custom objects (which will themselves conform to Encodable
).
The Challenge is what type should I declare the dictionary to be:
[String: Any]
, it won't know how to encode Any
, and if I have to cast it into an actual concrete type, it kind of defeats the purpose of generics[String: Encodable]
, it will crash at run time saying
Encodable doesn't conform to itself, which is understandable as it
needs a concrete typeIn order to tackle this, I thought of creating a wrapper: i.e A protocol with an associated type or a struct with generic type value:
struct Serializable<T: Encodable> {
var value: T?
init(value: T) {
self.value = value
}
}
But the problem remains, while declaring the type of the aforementioned dictionary, I still have to supply the concrete type..
var dictionary: [String: Serializable<X>]
What should 'X' be here, Or, what's the correct way to achieve this? What am I missing?
Two possible approaches:
You can create dictionary whose values are Encodable
wrapper type that simply encodes the underlying value:
struct EncodableValue: Encodable {
let value: Encodable
func encode(to encoder: Encoder) throws {
try value.encode(to: encoder)
}
}
Then you can do:
let dictionary = [
"foo": EncodableValue(value: Foo(string: "Hello, world!")),
"bar": EncodableValue(value: Bar(value: 42)),
"baz": EncodableValue(value: "qux")
]
let data = try! JSONEncoder().encode(dictionary)
You can define your own Codable
type instead of using dictionary:
struct RequestObject: Encodable {
let foo: Foo
let bar: Bar
let baz: String
}
let requestObject = RequestObject(
foo: Foo(string: "Hello, world!"),
bar: Bar(value: 42),
baz: "qux"
)
let data = try! JSONEncoder().encode(requestObject)
Needless to say, these both assume that both Foo
and Bar
conform to Encodable
.