简体   繁体   中英

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 ie

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?

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}

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 

就是这样

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

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)
}

this.

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

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)
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM