如何从Swift中的Brawl Stars API解析嵌套的JSON数据?

问题描述

https://pillow.readthedocs.io/en/4.0.x/reference/Image.html#PIL.Image.Image.paste。我创建了一个帐户->文档->如果您想尝试,请尝试

这是我要解析的JSON的一部分。我想在“ starPowers”数组以及“ gadgets”数组中打印名称

{
   "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的第一种方法,但是我找不到在“ starPower”或“ gadgets”数组中打印“ name”的方法

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处理失败:由于缺少数据而无法读取数据”。 (声明)

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

对于Swift和StackOverflow来说,我仍然还是个新手,所以对您的帮助或反馈将不胜感激。谢谢!

解决方法

在使用Codable API时,您要对所看到的数据进行 all 建模。所以这个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对象),其值是项目数组。您可以制作一个{{1} }结构来解决该问题,或者您可以执行以下操作:

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) } 处理,因为我假设获取数据可以正常工作并且是正确的。您可能应该检查这些假设并使用类似的构造分别为tryif-let

,

将可编码结构的属性命名为与相应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的一部分。

另一个提示:在命名结构时使用单数形式,因此小工具的一个元素是小工具。解码器不在乎您如何命名结构,而只在乎属性