fbpx
How to parse JSON in iOS using Swift

How to parse JSON in iOS using Swift

Today, I’m going to show you how to parse JSON in your iOS app without using any 3rd party library.

There are are two ways to parse a JSON natively in iOS:

  • JSONSerialization: This is the old fashion way to parse JSON. It’s recommended only when you want to parse one or two JSON objects.
  • JSONDecoder: This method is available only in Swift 4 and later. You create your model and after parsing the JSON you’ll get an object with all the fields already filled.

In this tutorial, I’ll cover 3 cases that may you face when you’re trying to parse JSON:

  • Simple JSON: Just a simple JSON without any complex structure
  • Array JSON: The JSON structure begins with an array and without a key
  • Nested JSON: Includes nested objects

Simple JSON

A simple JSON doesn’t have any complex structure, like arrays, nested objects e.t.c, and it looks like that:

{
    "id": "1",
    "employee_name": "Jack Full",
    "employee_salary": "300800",
    "employee_age": "61"
}

• JSONSerialization Method

To parse JSON with the JSONSerialization method, you take the data after the HTTP request, and then you parse JSON like that:

if let json = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] {
    // ID
    let id = json["id"] as? String ?? "N/A"
    print("ID: \(id)")
    
    // Employee Name
    let employeeName = json["employee_name"] as? String ?? "N/A"
    print("Employee Name: \(employeeName)")
    
    // Employee Salary
    let employeeSalary = json["employee_salary"] as? String ?? "N/A"
    print("Employee Salary: \(employeeSalary)")
    
    // Employee Age
    let employeeAge = json["employee_age"] as? String ?? "N/A"
    print("Employee Age: \(employeeAge)")
}

Tip: When there are curly brackets { } with JSON objects inside. We’re parsing them using Dictionary –> ‘[String: Any]’

• JSONDecoder Method

In JSONDecoder method, we create a model that conforms the Codable protocol. In this example, we call it SimpleJSONModel:

class SimpleJSONModel: Codable {
    let employee_id: String
    let employee_name: String
    let employee_salary: String
    let employee_age: String

    
    enum CodingKeys: String, CodingKey {
        case employee_id = "id"
        case employee_name
        case employee_salary
        case employee_age
    }
}

Tip: If you don’t want to create the model manually, you can use the Quicktype.io to generate it.

As you see, every declared value in the model has the same name with the JSON keys, except the ‘id‘ (It’s called ‘employee_id‘ in our model).

To be able to get the ‘id‘ from the JSON using the ‘employee_id‘ in our model, we use a nested enumeration named CodingKeys that conforms to the CodingKey protocol, and we rename it.

Then using the JSONDecoder class and the model we created before, we parse JSON using the data from the HTTP request:

let jsondecode = try! JSONDecoder().decode(SimpleJSONModel.self, from: data)

// ID
let id = jsondecode.employee_id
print("ID: \(id)")

// Employee Name
let employeeName = jsondecode.employee_name
print("Employee Name: \(employeeName)")

// Employee Salary
let employeeSalary = jsondecode.employee_salary
print("Employee Salary: \(employeeSalary)")

// Employee Age
let employeeAge = jsondecode.employee_age
print("Employee Age: \(employeeAge)")

If you don’t know how to make HTTP requests, I recently wrote how to do it using Alamofire and URLSession

Tip: When there are square brackets [ ] with JSON objects inside. We’re parsing them using Array –> ‘[Any]’

Array JSON

Sometimes, you might see a JSON start with an array and without having a key:

[
    {
        "id": "1",
        "employee_name": "Tiger Nixon",
        "employee_salary": "320800",
        "employee_age": "61"
    },
    {
        "id": "2",
        "employee_name": "Garrett Winters",
        "employee_salary": "170750",
        "employee_age": "63"
    },
    // ...
]

• JSONSerialization Method

With the JSONSerialization method to parse this type of JSON, you need to convert the JSON array as [Any], and then get the JSON objects inside the for loop:

if let json = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [Any] {
    for item in json {
        if let object = item as? [String: Any] {
            // ID
            let id = object["id"] as? String ?? "N/A"
            print("ID: \(id)")
            
            // Employee Name
            let employeeName = object["employee_name"] as? String ?? "N/A"
            print("Employee Name: \(employeeName)")
            
            // Employee Salary
            let employeeSalary = object["employee_salary"] as? String ?? "N/A"
            print("Employee Salary: \(employeeSalary)")
            
            // Employee Age
            let employeeAge = object["employee_age"] as? String ?? "N/A"
            print("Employee Age: \(employeeAge)")
            
            // Save data using your Model
            
        }
    }
    
    // Reload data of TableView/CollectionView
    
}

• JSONDecoder Method

With the JSONDecoder method, we create a model that conforms the Codable protocol for each item of the JSON array. In this example, we call it ArrayJSONModel:

struct ArrayJSONModel: Codable {
    let employee_id: String
    let employee_name: String
    let employee_salary: String
    let employee_age: String

    enum CodingKeys: String, CodingKey {
        case employee_id = "id"
        case employee_name
        case employee_salary
        case employee_age
    }
}

Then we parse JSON using this model inside of an array (e.g. [ArrayJSONModel]):

let json = try! JSONDecoder().decode([ArrayJSONModel].self, from: data)

for item in json {
    // ID
    let id = item.employee_id
    print("ID: \(id)")
    
    // Employee Name
    let employeeName = item.employee_name
    print("Employee Name: \(employeeName)")
    
    // Employee Salary
    let employeeSalary = item.employee_salary
    print("Employee Salary: \(employeeSalary)")
    
    // Employee Age
    let employeeAge = item.employee_age
    print("Employee Age: \(employeeAge)")
    
    // Save data using your Model
}

// Reload data of TableView/CollectionView

Nested JSON

When a JSON object is inside another JSON object, it’s called ‘nested’, and will look like the following JSON structure:

{
    "data": [
        {
            "id": "1",
            "employee": {
                "name": "Tiger Nixon",
                "salary": {
                    "usd": 320800,
                    "eur": 273545
                },
                "age": "61"
            }
        },
        {
            "id": "2",
            "employee": {
                "name": "Garrett Winters",
                "salary": {
                    "usd": 170750,
                    "eur": 145598
                },
                "age": "63"
            }
        },
        // ...
    ]
}

• JSONSerialization Method

To parse this complex JSON nesting of objects and array using the JSONSerialization method, you just get the data after the HTTP request, and then:

var employeeName: String!
var employeeSalaryUSD: Int!
var employeeSalaryEUR: Int!
var employeeAge: String!

let json = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]

if let data = json?["data"] as? [Any] {
    
    for item in data {
        if let object = item as? [String: Any] {
            // ID
            let id = object["id"] as? String ?? "N/A"
            print("ID: \(id)")
            
            if let employee = object["employee"] as? [String: Any] {
                // Employee Name
                let employeeName = employee["name"] as? String ?? "N/A"
                self.employeeName = employeeName
                print("Employee Name: \(employeeName)")
                
                // Salary
                if let salary = employee["salary"] as? [String: Any] {
                    // Employee Salary in USD
                    if let employeeSalaryUSD = salary["usd"] as? Int {
                        self.employeeSalaryUSD = employeeSalaryUSD
                        print("Employee Salary in USD: \(employeeSalaryUSD)")
                    }
                    
                    // Employee Salary in EUR
                    if let employeeSalaryEUR = salary["eur"] as? Int {
                        self.employeeSalaryEUR = employeeSalaryEUR
                        print("Employee Salary in EUR: \(employeeSalaryEUR)")
                    }
                }
                
                // Employee Age
                let employeeAge = employee["age"] as? String ?? "N/A"
                self.employeeAge = employeeAge
                print("Employee Age: \(employeeAge)")
            }
            
            // Save data using your Model
        }
    }
    
    // Reload data of TableView/CollectionView
}

• JSONDecoder Method

With the JSONDecoder method, first, we create a model, in this example called NestedJSONModel:

struct NestedJSONModel: Codable {
    let data: [Datum]

    enum CodingKeys: String, CodingKey {
        case data
    }
}

// MARK: - Datum
struct Datum: Codable {
    let employee_id: String
    let employee: Employee

    enum CodingKeys: String, CodingKey {
        case employee_id = "id"
        case employee
    }
}

// MARK: - Employee
struct Employee: Codable {
    let name: String
    let salary: Salary
    let age: String

    enum CodingKeys: String, CodingKey {
        case name
        case salary
        case age
    }
}

// MARK: - Salary
struct Salary: Codable {
    let usd: Int
    let eur: Int

    enum CodingKeys: String, CodingKey {
        case usd
        case eur
    }
}

Then with this model, we get the nested JSON objects inside the for loop of the ‘data‘ array:

let json = try! JSONDecoder().decode(NestedJSONModel.self, from: data)

let dataArray = json.data

for item in dataArray {
    // ID
    let id = item.employee_id
    print("ID: \(id)")
    
    // Employee Name
    let employeeName = item.employee.name
    print("Employee Name: \(employeeName)")
    
    // Employee Salary in USD
    let employeeSalaryUSD = item.employee.salary.usd
    print("Employee Salaray USD: \(employeeSalaryUSD)")
    
    // Employee Salary in EUR
    let employeeSalaryEUR = item.employee.salary.eur
    print("Employee Salaray EUR: \(employeeSalaryEUR)")
    
    // Employee Age
    let employeeAge = item.employee.age
    print("Employee Age: \(employeeAge)")
    
    // Save data using your Model
}

// Reload data of TableView/CollectionView
You can find the final project here

If you have any questionsplease feel free to leave a comment below

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments