Parsing JSON Arrays in Swift

Introduction and Context Setting

Welcome to this lesson on parsing arrays within JSON structures using Swift. JSON arrays are vital for containing collections of data elements, such as lists of employees or products. Mastering how to parse these arrays effectively is key to handling complex data structures in real-world applications. In this lesson, we will build upon what you've previously learned by exploring how to extract data from JSON arrays using Swift, focusing on Swift’s Decodable protocol.

Understanding JSON Arrays

A JSON array is a sequence of ordered items enclosed within square brackets [ ]. Each item in an array can be an object, a string, a number, or even another array. JSON arrays are perfect for storing lists or sequences.

Here's a simple example of a JSON array:

[
    {"name": "John", "age": 30},
    {"name": "Jane", "age": 25}
]

This JSON array contains two objects, each representing an individual with a name and age attribute. Understanding this structure is essential as we dive into parsing more complex, nested arrays in subsequent sections.

Parsing JSON Arrays with Swift

Now, let’s process a JSON array using Swift's Decodable protocol. In Swift, JSON data can have a top-level structure as either an object ({}) or an array ([]). When processing JSON arrays using Swift's Decodable protocol, ensure your JSON structure in data.json is an object at the top level with a departments key. If your JSON begins directly with an array, you must decode it using [Department].self instead of Company.self. This adjustment ensures Swift correctly interprets the data as an array of objects rather than a single object containing an array.

Consider the following JSON in a file named data.json:

{
    "departments": [
        {
            "name": "Research and Development"
        },
        {
            "name": "Marketing"
        }
    ]
}

Here's an example using Decodable in Swift to parse this JSON:

import Foundation

struct Department: Decodable {
    let name: String
}

struct Company: Decodable {
    let departments: [Department]
}

let filePath = "data.json"
if let jsonData = FileManager.default.contents(atPath: filePath) {
    do {
        let company = try JSONDecoder().decode(Company.self, from: jsonData)
        for department in company.departments {
            print("Department:", department.name)
        }
    } catch {
        print("Error decoding JSON:", error)
    }
}

Output:

Department: Research and Development
Department: Marketing

In this example, the JSON array departments is mapped to a Swift struct, and we iterate over each department to print its name. Again, if your actual JSON is a top-level array instead of an object, decode [Department].self rather than using a Company struct.

Working with Nested JSON Arrays

Parsing nested JSON arrays requires handling more complex structures where arrays contain additional arrays or objects. This added complexity enables a richer data representation. Make sure your JSON is structured as shown below (an object at the top level). If your own data is a top-level array, decode [Company].self instead of a single Company.

Consider the following nested JSON structure in data.json:

{
    "company": "Tech Innovations Inc.",
    "headquarters": {
        "city": "San Francisco",
        "state": "CA"
    },
    "departments": [
        {
            "name": "Research and Development",
            "head": "Alice Johnson",
            "employees": [
                {"name": "John Doe", "position": "Engineer", "experience": 5},
                {"name": "Jane Smith", "position": "Research Scientist", "experience": 7}
            ]
        },
        {
            "name": "Marketing",
            "head": "Michael Brown",
            "employees": [
                {"name": "Chris Lee", "position": "Marketing Specialist", "experience": 3},
                {"name": "Sara Connor", "position": "Brand Manager", "experience": 6}
            ]
        }
    ]
}

Here's how to navigate these nested structures using Decodable:

import Foundation

struct Employee: Decodable {
    let name: String
    let position: String
    let experience: Int
}

struct Department: Decodable {
    let name: String
    let head: String
    let employees: [Employee]
}

struct Company: Decodable {
    let company: String
    let headquarters: Headquarters
    let departments: [Department]
}

struct Headquarters: Decodable {
    let city: String
    let state: String
}

let filePath = "data.json"
if let jsonData = FileManager.default.contents(atPath: filePath) {
    do {
        let company = try JSONDecoder().decode(Company.self, from: jsonData)
        for department in company.departments {
            for employee in department.employees {
                print("Employee:", employee.name, "Experience:", employee.experience)
            }
        }
    } catch {
        print("Error decoding JSON:", error)
    }
}

Output:

Employee: John Doe Experience: 5
Employee: Jane Smith Experience: 7
Employee: Chris Lee Experience: 3
Employee: Sara Connor Experience: 6

This approach lets us seamlessly move through complex JSON arrays, enabling the efficient extraction of data from nested structures. If your data is a top-level array of these objects (instead of a single object), change the decoding to [Company].self and iterate accordingly.

Real-World Application: Calculating Average Experience

Summary and Preparation for Practice

In this lesson, we've expanded your comprehension of JSON arrays in Swift, from parsing simple sequences to handling intricate nested structures. You've learned how to apply these concepts by calculating the average experience of employees, demonstrating a real-world use case. These skills are indispensable as you encounter complex data paradigms in practice.

Continue onto the practice exercises to apply these skills in varied situations, reinforcing your learning and expertise in Swift.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal