Skip to content

JSON Parsing Cheat Sheet

Ludwig Vantours edited this page Apr 25, 2020 · 3 revisions

JSON Parsing Cheat Sheet

JSON Values and Their Corresponding Swift Types

JSON Values Swift Type
Anything contained in braces, { ... } struct (usually), class, or dictionary
Anything contained in brackets [ ... ] Array
Anything contained in quotes " ... " String
Any whole number, e.g. 10 Int
Anything with a decimal, e.g. 25.2 Float or Double
A boolean (without quotes), true or false Bool

Decoding a JSON Object

We're just storing a simple JSON object using a Swift string.

let json = """
{
    "model": "iPhone XS,
    "released": 2018
}
""".data(using: .utf8)!

We represent this object in Swift using a struct

struct Phone: Codable {
    let model: String
    let released: Int
}

And decode it using a JSONDecoder, passing in Phone.self as the type to parse into. We should handle parsing errors with do catch.

do {
    let decoder = JSONDecoder()
    let phone = try decoder.decode(Phone.self, from: json)
    print(phone)
} catch {
    print(error)
}

What if I want/need my Swift properties to be something other than the JSON keys?

Use a CodingKeys enum. Here we change released to releaseYear. In some JSON objects, it will be necessary to use CodingKeys if the keys are not valid Swift property names.

struct Phone: Codable {
    let model: String
    let released: Int

    enum CodingKeys: String, CodingKey {
        case model
        case releaseYear = "released"
    }
}

What if there's a nested object?

For example, if we added a JSON object to represent the screen resolution.

let json = """
{
    "model": "iPhone XS",
    "released": 2018,
    "screen_resolution": {
        "width": 1125,
        "height": 2436
    }
}
""".data(using: .utf8)!

Create a Codable struct representing the properties in each level of indenting. Start with the innermost. The resolution...

struct Resolution: Codable {
    let width: Int
    let height: Int
}

And for the root object, which represents the phone. Notice that a property is added for screenResolutin, and it's also added to the CodingKeys enum.

struct Phone: Codable {
    let model: String
    let releaseYear: Int
    let screenResolution: Resolution
    
    enum CodingKeys: String, CodingKey {
        case model
        case releaseYear = "released"
        case screenResolution = "screen_resolution"
    }
}

What if there's an array?

Here, we have multiple JSON objects in an array

let json = """
[
    {
        "model": "iPhone XS",
        "released": 2018,
        "screen_resolution": {
            "width": 1125,
            "height": 2436
        }
    },
    {
        "model": "iPhone 8",
        "released": 2017,
        "screen_resolution": {
            "width": 750,
            "height": 1920
        }
    }
]
""".data(using: .utf8)!

Modify the parsing line to be an array of whatever the objects are.

let phone = try decoder.decode([Phone].self, from: json)

Any Codable type, including the basic types, means that an array of that type is also Codable!

What if I need to know the key names?

Some JSON will be structured where the key names won't always be known (common in NoSQL databases like Firebase). For example, these "users" are values for keys, which are their user IDs.

let users = """
{
    "25801": {
        "display_name": "Owen",
        "joined": 2015
    },
    "39447": {
        "display_name": "Jessica",
        "joined": 2016
    }
}
""".data(using: .utf8)!

The JSON objects stored as values still need a Codable struct.

struct User: Codable {
    let displayName: String
    let joined: Int

    enum CodingKeys: String, CodingKey {
        case displayName = "display_name"
        case joined
    }
}

But we would parse this into a dictionary with string keys and User values.

let usersDict = try decoder.decode([String: User].self, from: users)

And use the keys and values properties of Swift dictionaries to access the keys and values directly.

usersDict.keys
usersDict.values