Как мне проанализировать вложенные данные JSON из Brawl Stars api в Swift?

#json #swift #jsondecoder

#json #swift #jsondecoder

Вопрос:

Веб-сайт API, который я использовал. Я создал учетную запись -> Документация -> Brawlers, если вы хотите попробовать

Вот часть JSON, которую я хочу проанализировать. Я хочу напечатать имя внутри массива «starPowers», а также массива «гаджеты».

 {
   "items":[
      {
         "id":16000014,
         "name":"BO",
         "starPowers":[
            {
               "id":23000090,
               "name":"CIRCLING EAGLE"
            },
            {
               "id":23000148,
               "name":"SNARE A BEAR"
            }
         ],
         "gadgets":[
            {
               "id":23000263,
               "name":"SUPER TOTEM"
            },
            {
               "id":23000289,
               "name":"TRIPWIRE"
            }
         ]
      }
   ]
}
  

Я попробовал этот первый способ анализа JSON, который сработал, но я не смог найти способ напечатать «name» внутри массива «StarPower» или «gadgets».

 import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let apiToken = "abcdefg"

        if let url = URL(string: "https://api.brawlstars.com/v1/brawlers") {
            
            var request = URLRequest(url: url)
            request.httpMethod = "GET"
            request.addValue("Bearer (apiToken)", forHTTPHeaderField: "authorization")
            request.addValue("application/json", forHTTPHeaderField: "Accept")

            URLSession.shared.dataTask(with: request) { (data, response, error) in
                if error != nil {
                    print(error!)
                } else {
                    guard let data = data else {return}

                    do {
                        let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as AnyObject
                        print(jsonResult)
                        if let items = jsonResult["items"] as? NSArray {
                            for item in items as [AnyObject] {
                                if let name = item["name"] {
                                    print(name!)
                                }
                                if let gadgets = item["gadgets"] {
                                    print(gadgets!)
                                }
                                if let starPowers = item["starPowers"]{
                                    print(starPowers!)
                                }
                            }
                        }
                 } catch {
                        print("JSON processing failed: (error.localizedDescription)")
                    }
                }
            }.resume()
        } else {
            print("Something went wrong")
        }
    }
}
  

Итак, я добавил еще один файл с этими данными:

 struct StarPowers: Codable {
    let starPowerName: String
}

struct Gadgets: Codable {
    let gadgetName: String
}

struct Items: Codable {
    let name: String
    let starPowers: [StarPowers]
    let gadgets: [Gadgets]
} 
  

И заменил код внутри инструкции do следующим образом, но он вернул «Сбой обработки JSON: данные не могут быть прочитаны, потому что они отсутствуют». (Оператор Catch)

 let items = try JSONDecoder().decode(Items.self, from: data)
print(items.name.first ?? "")
  

Я все еще довольно новичок в Swift в целом, а также в StackOverflow, поэтому буду очень признателен за любую помощь или отзыв. Спасибо!

Ответ №1:

При использовании Codable API требуется моделировать все данные, которые вы видите. Итак, этот JSON:

 {
   "items":[
      {
         "id":16000014,
         "name":"BO",
         "starPowers":[
            {
               "id":23000090,
               "name":"CIRCLING EAGLE"
            },
            {
               "id":23000148,
               "name":"SNARE A BEAR"
            }
         ],
         "gadgets":[
            {
               "id":23000263,
               "name":"SUPER TOTEM"
            },
            {
               "id":23000289,
               "name":"TRIPWIRE"
            }
         ]
      }
   ]
}
  

должно привести к этим структурам:

 //This represents one star power
struct StarPower: Codable {
    let id: Int
    let name: String
}
//This represents one gadget
struct Gadget: Codable {
    let id: Int
    let name: String
}
//This represents one "item" (I think they're brawlers, but I didn't make an account so I can't confirm what the API calls them
struct Item: Codable {
    let id: Int
    let name: String
    let starPowers: [StarPower]
    let gadgets: [Gadget]
}
  

Однако предоставленный вами отрывок на самом деле имеет тип [String:[Item]] (словарь (он же объект JSON) с одним строковым ключом, значение которого представляет собой массив элементов. Вы могли бы создать Codable структуру для обработки этого, или вы можете просто сделать это:

 let decoded = try! JSONDecoder().decode([String:[Item]].self, from: data)
let items = decoded["items"]!
//items is an array of type [Item]
//  Using your example, it would only have one element.
let element = items.first!
for starPower in element.starPowers {
    print(starPower.name)
}
for gadget in element.gadgets {
    print(gadget.name)
}
  

(имейте в виду, что я принудительно разворачиваю и try редактирую, потому что я предполагаю, что выборка данных прошла нормально и что это правильно. Вероятно, вам следует проверить эти предположения и использовать такие конструкции, как if-let и do-catch )

Ответ №2:

Назовите свойства ваших кодируемых структур точно так же, как ключи в соответствующем JSON:

 struct StarPower: Codable {
    let name: String
}

struct Gadget: Codable {
    let name: String
}

struct Item: Codable {
    let name: String
    let starPowers: [StarPower]
    let gadgets: [Gadget]
} 
  

Декодер не смог найти данные, потому что «gadgetName» и «starPowerName» не являются частью предоставленного вами JSON.

Еще один совет: используйте единственное число при именовании структур, поэтому одним из элементов гаджетов является гаджет. декодеру все равно, как вы называете свои структуры, его интересуют только свойства