Encoding and decoding JSON in Swift

by @ralfebert · updated November 20, 2021
Xcode 13 & iOS 15
Developers without prior iOS knowledge
English

JSON data

The JSON format (JavaScript Object Notation) is very well suited for the exchange of structured data due to its easily readable text form. Data is represented via associative arrays {...} and lists [...]:

[
    {
        "name": "Bob",
        "age": 32,
        "phone": [
            { "type": "mobile", "number": "0123-456789" },
            { "type": "work", "number": "040-456789" }
        ]
    },
    {
        "name": "Alice",
        "age": 56,
        "address": {
            "street": "Musterstrasse 12",
            "zip": "20095",
            "city": "Hamburg"
        }
    }    
]

Handling JSON data in Swift

With the Foundation classes JSONDecoder and JSONEncoder, JSON data can be parsed in Swift and Swift values can be converted to JSON. It is recommended to define suitable data types as struct, which correspond 1:1 to the structure from the JSON. These must be declared conforming to the Codable protocol:

import Foundation

struct Person: Codable {
    let name: String
    let age: Int
    let phone: [Phone]?
    let address: Address?
}

struct Address: Codable {
    let street, zip, city: String
}

struct Phone: Codable {
    let type, number: String
}

A JSON file included in the Xcode project and shipped with the app could be parsed as follows:

if let jsonURL = Bundle.main.url(forResource: "persons", withExtension: "json") {
    let jsonData = try Data(contentsOf: jsonURL)
    let jsonDecoder = JSONDecoder()
let persons = try jsonDecoder.decode([Person].self, from: jsonData)
}

A Codable object can be encoded as JSON as follows:

let jsonEncoder = JSONEncoder()
let jsonResultData = try jsonEncoder.encode(persons)

Customize names of properties, additional properties

A CodingKeys enum can be used to explicitly set the names of the properties. For this, it is necessary to include all properties that should be included in the JSON output. Properties that are not contained in CodingKeys will be ignored. This allows properties to be added to a type that should not be included in the JSON output:

struct Person: Codable {
    let name: String
    let age: Int
    var someOtherAttribute: String?

    enum CodingKeys: String, CodingKey {
    case name = "name"
    case age = "ageYears"
}
}

Naming of properties: Snake-case vs. Camel-case

Properties in JSON data often follow the Snake-case naming convention (e.g. phone_number). Following the Swift naming conventions, a corresponding property would be named according to the Camel-case naming convention (e.g. phoneNumber). Conveniently, a corresponding conversion of the naming conventions can be configured:

jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
jsonEncoder.keyEncodingStrategy = .convertToSnakeCase

Formatted output

With outputFormatting the output of the JSON serialization can be configured:

jsonEncoder.outputFormatting = .prettyPrinted

Date values

For the non-standard encoding of date values in JSON, a corresponding option can be set:

jsonEncoder.dateEncodingStrategy = .iso8601
jsonDecoder.dateDecodingStrategy = .iso8601

Customize the encoding

If the structure of the Swift type differs from its encoded form, it is possible to define your own encoding and decoding logic:

Adjusting the encoding logic is only useful up to a point. For very irregularly structured JSON data formats, the JSONSerialization class might be an alternative. This doesn't map to Swift types but returns values as dictionaries. Another way to deal with such data is to use the open-source framework SwiftyJSON, which provides a convenient API for dynamic access to JSON data.

Tools

Generate Codable types

With quicktype Swift code for types can be generated using sample JSON data:

This can also be done using a command line tool, for example:

brew install quicktype
quicktype https://www.ralfebert.de/examples/v3/countries.json --lang swift --no-initializers --no-coding-keys --density normal --acronym-style camel

Display JSON data in a structured way

The plug-ins JSONView for Chrome/Firefox or SimplyJSON for Safari can be used to display JSON data formatted in the browser:

Next

→ Loading JSON data with async/await