Encoding awkward types with minimal boilerplate using `withUnsafeBytes`
For many years now, the go-to way of encoding and decoding Swift types to
JSON has been the
This gave a more type safe way of handling json than its predecessor
JSONSerialization, which spat out
[String: Any] dictionaries. Conversely
Codable handles conversion upfront, dealing with all the type conversion, and failing if the object cannot be converted successfully.
An additional advantage of
Codable is that conformance can be synthesised for many objects if they only contain other
Codable or simple types.
One place common place where
Codable conformance cannot be synthesised is when using enums with associated values. The complier will tell us that the type does not conform to
There are a number of ways of getting around this issue, the most common being to use custom implementations of the
Encodable protocols. One implementation might look something like this:
Despite the fact that this adds a tremendous amount of boilerplate code, it’s also not reusable. If we have another enum with a different format, we would have to re-write this all again.
Proposals have been made to add
Codable synthesis to enums with associated values but as of yet, nothing has been added to the Swift language.
withUnsafeBytes to the rescue!
One simple solution to solve the problem of reusable conformance for varying types is to use
withUnsafeBytes. This allows us to access the underlying memory for a Swift object. We can then use that underlying memory directly or as part of a larger JSON object. Here is a simple (and reusable) protocol that does the encoding for us:
It should be noted that this is not a robust way of serialising data, just a really simple one. Ideally, this data should not be written to disk or transferred between devices as the data format could change between Swift versions or between different devices. Having said that, newer versions of Swift with ABI stability may mitigate this concern somewhat.
I will be using this method to transfer data between my Unit Tests and my Application for testing under different launch conditions. I consider this relatively safe as the device type and Swift version will always match.