Snake case is now just a few keystrokes away.
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 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.
SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!
Sponsor Hacking with Swift and reach the world's largest Swift community!
Paul Hudson is the creator of Hacking with Swift, the most comprehensive series of Swift books in the world. He's also the editor of Swift Developer News, the maintainer of the Swift Knowledge Base, and a speaker at Swift events around the world. If you're curious you can learn more here.
Link copied to your pasteboard.