Skip to main content

Swift 4.1 improves Codable with keyDecodingStrategy

About 2 minSwiftArticle(s)bloghackingwithswift.comcrashcourseswiftiosxcode

Swift 4.1 improves Codable with keyDecodingStrategy 관련

Swift > Article(s)

Article(s)

Swift 4.1 improves Codable with keyDecodingStrategy – Hacking with Swift
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 (apple/swift)open in new window 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.


이찬희 (MarkiiimarK)
Never Stop Learning.