Swift 4.1 improves Codable with keyDecodingStrategy
Swift 4.1 improves Codable with keyDecodingStrategy 관련
Swift 4.0 brought many great new features, including multi-line strings, better keypaths, and lots of improved dictionary functionality. But it also gave us Codable
for the first time: by far the easiest, safest way to convert Swift objects into JSON and XML.
However, Codable
had one particular annoyance that hit most users: if your JSON used snake_case for its key names and your Swift code used camelCase for its property names, Codable
wouldn’t be able to convert between the two – you needed to create your own CodingKeys
mapping to explain how the two matched up.
Well, Swift 4.1 has fixed this beautifully: along with awesome new features of its own there’s a new keyDecodingStrategy
property on JSONDecoder
that can automatically convert between snake_case and camelCase if you need it. The inverse property, keyEncodingStrategy
, also exists on JSONEncoder
so you can convert your Swift camelCase names back into snake_case.
Enough chat – let’s look at a practical example. Create a new Playground and give it this JSON string:
let jsonString = """
[
{
"name": "MacBook Pro",
"screen_size": 15,
"cpu_count": 4
},
{
"name": "iMac Pro",
"screen_size": 27,
"cpu_count": 18
}
]
"""
let jsonData = Data(jsonString.utf8)
That stores an array of two items, each describing a Mac. As you can see, both screen_size
and cpu_count
use snake case – words are all lowercased, with underscores separating them. I’ve added a conversion to Data
at the end, because that’s what JSONDecoder
works with.
Now, we want to convert that JSON into an array of Mac
instances using this struct:
struct Mac: Codable {
var name: String
var screenSize: Int
var cpuCount: Int
}
That follows standard Swift naming conventions, so the property names are all camelCased – words have no separators, but second and subsequent words all start with a capital letter.
In Swift 4.0 you might try to decode that JSON like this:
let decoder = JSONDecoder()
do {
let macs = try decoder.decode([Mac].self, from: jsonData)
print(macs)
} catch {
print(error.localizedDescription)
}
However, that code won’t work because Codable
doesn’t know how to map camelCase keys to the snake_case. This is where the new keyDecodingStrategy
property comes in: it’s set to .useDefaultKeys
by default, which does a direct mapping of JSON names to Swift properties. However, if you change it to .convertFromSnakeCase
then the above code works immediately because Codable
handles the name conversion for us.
So, add this line just before the start of the do
block:
decoder.keyDecodingStrategy = .convertFromSnakeCase
When you want to go back the other way – to convert a Codable
struct with camelCase properties back to JSON with snake_case keys, set the keyEncodingStrategy
to .convertToSnakeCase
like this:
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let encoded = try encoder.encode(macs)
If you have more advanced uses – perhaps you prefer SCREAMING_SNAKE_CASE for some reason? – you can also specify a custom key strategy, but looking at the tests for that (apple/swift
) it seems a rather involved thing to do, at least for now.
For more on the new features in Swift 4.1, see our article what's new in Swift 4.1.