NEW! Check out my latest book, Testing Swift! >>

Swift 4.1 improves Codable with keyDecodingStrategy

Paul Hudson       @twostraws

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.

 

MASTER SWIFT NOW
Buy Testing Swift Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

About the author

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 Mario Kart world champion. OK, so that last part isn't true. If you're curious you can learn more here.

Was this page useful? Let me know!

Average rating: 4.0/5

Click here to visit the Hacking with Swift store >>