Decodable
Convert a JSON into an object.
Decodable
Convert a JSON into an object.
0
0
Checkbox to mark video as read
Mark as read

To convert a JSON into an object that we've defined we can use the Decodable protocol, which allows us to easily use the JSONDecoder object to perform the conversion.

Converting a JSON to an Object

The requirements for our object are:

  • The properties must have the same names as the parameters to be converted.
  • The property types must match the types of the values to be converted.
  • It must implement the Decodable protocol.

We'll define our object by implementing the Decodable protocol, and also a String in JSON format, which we'll use as an example.

struct Person: Decodable {
    let name: String
    let age: Int
}

let jsonString = """
{
    "name": "Pablo",
    "age": 19
}
"""

First, we need to convert our String into a Data object. This step is usually unnecessary when the response already comes as Data from the server, but for this example, we will convert it ourselves.

The second step is to use the decode(_:from:) function from the JSONDecoder object. The decode(_:from:) function has two parameters: the first specifies the type of object we want to obtain (in this case, Person.self), and the second is our data. This function also returns errors, so we'll use try? as we've seen in previous articles.

if let data = jsonString.data(using: .utf8) {

    if let person = try? JSONDecoder().decode(Person.self, from: data) {
        print(person.name)
        print(person.age)
    }
}

Converting Arrays

In the case of having a JSON composed of an Array, we follow the same process, except the type of variable we want to obtain will be [Person].self.

let jsonArrayString = """
[
    {
        "name": "Pablo",
        "age": 19
    },
    {
        "name": "Andrea",
        "age": 23
    },
    {
        "name": "Miguel",
        "age": 31
    },
]
"""

if let data = jsonArrayString.data(using: .utf8) {

    if let persons = try? JSONDecoder().decode([Person].self, from: data) {
        for person in persons {
            print(person.name)
            print(person.age)
        }
    }
}

// The console outputs:
// Pablo
// 19
// Andrea
// 23
// Miguel
// 31

Nested JSONs and Optionals

We can convert nested JSONs by defining the same structure in our objects. Let's see how we can have Person objects that, in addition to name and age, can have an object of type Pet.

We can define some properties as Optional, if an Optional parameter does not exist in our JSON, then the property value will be set to nil. However, if a property is not Optional and it's not found in our JSON, the entire conversion will fail, returning nil instead of an array.

struct Person: Decodable {
    let name: String
    let age: Int

    let pet: Pet?
}

struct Pet: Decodable {
    let name: String
}

let jsonArrayString = """
[
    {
        "name": "Pablo",
        "age": 19,
        "pet": {
            "name": "Danko"
        }
    },
    {
        "name": "Andrea",
        "age": 23
    }
]
"""

if let data = jsonArrayString.data(using: .utf8) {

    if let persons = try? JSONDecoder().decode([Person].self, from: data) {
        for person in persons {
            print(person.name)
            print(person.age)
            print(person.pet?.name ?? "No Pet")
        }
    }
}

// The console outputs:
// Pablo
// 19
// Danko
// Andrea
// 23
// No Pet

Using Different Property Names

In some cases, we may receive JSONs with parameters that have names that we can't or don't want to use. It is possible to use different property names than those in the JSON by adding the following enum.

We'll define a case for each property we want to decode. The name of the case will be used to find that property in the JSON unless we assign a different one as a String.

struct Person: Decodable {
    let name: String
    let age: Int

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

In this example, we can have the age property, which will get its value from the years_old parameter.

{
    "name": "Pablo",
    "years_old": 19
}

course

Quiz Time!

0 Comments

Join the community to comment
Sign Up
I have an account
Be the first to comment

Accept Cookies

We use cookies to collect and analyze information on site performance and usage, in order to provide you with better service.

Check our Privacy Policy