Reinier68
Reinier68

Reputation: 3282

How to retrieve values from a Nested JSON Swift

So I've been working with a nested JSON file (that I added locally to my project) in Swift. I've included a part of the JSON file I'm working on below. The data is structured as follows:

{
    "categories": [
                   {
                   "categoryName": "Albatrosses",
                   "exercisesInCategory": [
                                           "Wandering albatross",
                                           "Grey-headed albatross",
                                           "Black-browed albatross",
                                           "Sooty albatross",
                                           "Light-mantled albatross"
                                           ]
                   },
                   {
                   "categoryName": "Cormorants",
                   "exercisesInCategory": [
                                           "Antarctic shag",
                                           "Imperial shag",
                                           "Crozet shag"
                                           ]
                   },
                   {
                   "categoryName": "Diving petrels",
                   "exercisesInCategory": [
                                           "South Georgia diving petrel",
                                           "Common diving petrel"
                                           ]
                   },
                   {
                   "categoryName": "Ducks, geese and swans",
                   "exercisesInCategory": [
                                           "Yellow-billed pintail"
                                           ]
                   }
                   ]
}

In order to retrieve the data I made 2 structures that represent the data in the JSON so I can then retrieve values from it. These are as follows:

struct Response:Codable{
    let categories: [Categories]
}

struct Categories:Codable{
    let categoryName : String?
    let exercisesInCategory : [String]
}

The file name is fitnessData.json and I'm trying to retrieve the data from it by using this code:

    private func parse(){
    print("Retrieving JSON Data...")
    if let url = Bundle.main.url(forResource: "fitnessData", withExtension: "json") {

        do {
            let data = try Data(contentsOf: url)
            self.response = try JSONDecoder().decode(Response.self, from: data)

            if let responseJSON = self.response {

                print("The categories are: ", responseJSON.categories[1].categoryName!)
            }
        } catch {
            print(error)
        }
    }
}

The problem is that I would like to retrieve ALL the 'categoryName' values from the JSON file, and ALL the 'exercisesInCategory' values. But so far I've only managed to navigate towards a specific item in the JSON file and retrieving that item i.e.

responseJSON.categories[1].categoryName!

I would like to iterate over the JSON file to get all of the 'categoryName' values for example. However in order to do that I'd have to write something like this:

for value in responseJSON.categories[1].categoryName! {
                    print(value)
                }  

Where '1' represents all the values for the categories struct. The code above will obviously print only the categoryName of the second index in the categories array in the JSON file. Could someone point me in the right direction?

Upvotes: 2

Views: 2634

Answers (6)

RJ168
RJ168

Reputation: 1046

If you wanted to get all the categoryName and exercisesInCategory form JSON file, then you don't need to pass hard coded index. Use the following modified function, it will do the work..

private func parse(){
    print("Retrieving JSON Data...")
    if let url = Bundle.main.url(forResource: "fitnessData", withExtension: "json") {
        do {
            let data = try Data(contentsOf: url)
            let response = try JSONDecoder().decode(Response.self, from: data)

            for category in response.categories {
                print("Category Name: \(category.categoryName!)")

                for exercises in category.exercisesInCategory {
                    print("Exercise in category: \(exercises)")
                }
            }
        } catch {
            print(error)
        }
    }
}

Upvotes: 0

Robert Dresler
Robert Dresler

Reputation: 11210

If you iterate through the String, each item is single character of string.


You can iterate through categories array

for category in responseJSON.categories {
    print(category.categoryName ?? "No name")
}

To get all names, you can use compactMap which removes nil values from an array

let names = responseJSON.categories.compactMap { $0.categoryName }

Next:

  • If each category has its name, make type of this property non-optional String (then you can use map instead of compactMap)

  • I would improve your naming. Rename categoryName key of json to name using CodingKeys enum. Then you could do

    category.name
    

Upvotes: 0

istorry
istorry

Reputation: 48

this.

let categories = responseJSON.categories.map { $0.categoryName }
categories.forEach { print($0) }

Upvotes: 0

Midhun MP
Midhun MP

Reputation: 107221

You can do that like:

for category in responseJSON.categories {
     print(category.categoryName!)
}

Or you can use map function for getting all the categoryName like:

let categoryNames = responseJSON.categories.map {$0.categoryName}

Upvotes: 4

denis_lor
denis_lor

Reputation: 6547

If you would like to put both values in different arrays:

var categoryNameList = [String]
var excercisesInCategory = [[String]] 
for category in responseJSON.categories {
    categoryNameList.append(category.categoryName)
    excercisesInCategory.append(category. exercisesInCategory)
}

Upvotes: 0

Mohmmad S
Mohmmad S

Reputation: 5088

Simply like this.

response.categories.forEach { print($0.categoryName) }

Upvotes: 0

Related Questions