Как извлечь значения из вложенного JSON Swift

#ios #arrays #json #swift #dictionary

#iOS #массивы #json #swift #словарь

Вопрос:

Итак, я работал с вложенным файлом JSON (который я добавил локально в свой проект) в Swift. Я включил часть файла JSON, над которым я работаю, ниже. Данные структурированы следующим образом:

 {
    "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"
                                           ]
                   }
                   ]
}
  

Для извлечения данных я создал 2 структуры, которые представляют данные в JSON, чтобы затем я мог извлекать из него значения. Это следующие:

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

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

Имя файла — fitnessData.json и я пытаюсь извлечь из него данные с помощью этого кода:

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

Проблема в том, что я хотел бы извлечь ВСЕ значения ‘CategoryName’ из файла JSON и ВСЕ значения ‘exercisesInCategory’. Но пока мне удалось перейти только к определенному элементу в файле JSON и получить этот элемент, т.Е.

 responseJSON.categories[1].categoryName!
  

Я хотел бы выполнить итерацию по файлу JSON, чтобы получить все значения ‘CategoryName’, например. Однако для того, чтобы сделать это, мне пришлось бы написать что-то вроде этого:

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

Где ‘1’ представляет все значения для структуры categories. Приведенный выше код, очевидно, напечатает только CategoryName второго индекса в массиве categories в файле JSON. Может ли кто-нибудь указать мне правильное направление?

Ответ №1:

Вы можете сделать это следующим образом:

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

Или вы можете использовать функцию map для получения всего categoryName подобного:

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

Ответ №2:

Просто так.

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

Комментарии:

1. Спасибо за ваш вклад. Ответ кажется таким простым, все это время я пытался сделать это правильно в течение многих часов, ха-ха.

Ответ №3:

Если вы хотите поместить оба значения в разные массивы:

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

Ответ №4:

это.

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

Ответ №5:

Если вы выполняете итерацию по String , каждый элемент представляет собой один символ строки.


Вы можете выполнять итерации по categories массиву

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

Чтобы получить все имена, вы можете использовать, compactMap который удаляет nil значения из массива

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

Далее:

  • Если у каждой категории есть свое название, сделайте тип этого свойства необязательным String (тогда вы можете использовать map вместо compactMap )

  • Я бы улучшил ваше именование. Переименуйте categoryName ключ json в name используя CodingKeys enum. Тогда вы могли бы сделать

     category.name
      

Ответ №6:

Если вы хотели получить весь JSON-файл categoryName и exercisesInCategory сформировать его, то вам не нужно передавать жестко закодированный индекс. Используйте следующую модифицированную функцию, она выполнит всю работу..

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