如何解析这个 JSON 口袋妖怪字典?口袋妖怪 API (swift 3)

Posted

技术标签:

【中文标题】如何解析这个 JSON 口袋妖怪字典?口袋妖怪 API (swift 3)【英文标题】:How can I parse this JSON Pokemon Dictionary? Pokemon API (swift 3) 【发布时间】:2018-11-25 05:36:15 【问题描述】:

我在解析来自新版 Pokemon API 的 JSON 数据时遇到问题,特别是“type”键中的“name”值。

Json 看起来像这样:

"types": [
    
        "slot": 2,
        "type": 
            "name": "poison",
            "url": "https://pokeapi.co/api/v2/type/4/"
        
    ,
    
        "slot": 1,
        "type": 
            "name": "grass",
            "url": "https://pokeapi.co/api/v2/type/12/"
        
    
],
"weight": 69

在 Alamofire 中解析后,我得到了下一个解决方案:

if let types = dict["types"] as? [Dictionary<String, String>] , types.count > 0 

                if let type = types[0]["type"] as? Dictionary<String, String> 

                    if let name = type["name"] 
                        self._type = name.capitalized
                    
                

                print("TypeAA: \(self._type)")

             else 

                self._type = ""
            

而且这一行也不会被执行。 print("TypeAA: (self._type)") 请指教,如何正确解析并获取名为“type”的键中“name”的值?

【问题讨论】:

使用Decodable比手动解析响应要容易得多。 感谢@Kamran,但请就这些代码提出建议。 【参考方案1】:

您不能使用dict["types"] as? [Dictionary&lt;String, String&gt;],因为types 中的项目无法转换为Dictionary&lt;String, String&gt;item 有像 "slot": 2 这样的整数和字典 "type": ...。所以必须先转换为[String : Any]

if let types = dict["types"] as? [Any], types.count > 0 
    if let firstObject = (types.first as? [String : Any]),
        let type = firstObject["type"] as? [String : String],
        let name = type["name"] 
            self._type = name.capitalized
    

如果您想要每个项目的名称,则必须循环遍历 items 数组。

【讨论】:

您的解决方案有效,但您的陈述是错误的。 [Dictionary&lt;String, String&gt;] 也是一个字典数组。如果你检查first,检查空是多余的。【参考方案2】:

或者在这里尝试类似的东西:

if let types = dict["types"] as? [Any] 
    guard types.count > 0 else 
        return
    

    for elment in types 
        if let type = elment["type"] as? [String:Any] 
            let name = type["name"] as! String
            // Do what you want with it here
        
    

【讨论】:

【参考方案3】:

您可以使用 AlamofireObjectMapper 非常轻松地解析来自 Alamofire 的 JSON 响应。

class PokemonTypesResponse: Mappable 
    var types:[Types]?
    var weight:Int?

    required init?(map: Map)

    

    func mapping(map: Map) 
        types <- map["types"]
        weight <- map["weight"]
    


class Types: Mappable 
    var slot:Int?
    var name:String?
    var url:String?

    required init?(map: Map)

    

    func mapping(map: Map) 
        slot <- map["slot"]
        type <- map["type.name"]
        url  <- mapp["type.url"]
    

使用 alamofire 执行请求并使用

.responseArray  (response: DataResponse<[PokemonTypesResponse]>) in
switch response.result 
            case .success:
                //this is the response as PokemonTypesResponse
                response.result.value 
            case .failure(let error):
                print(error)
            

映射 JSON 结果 我没有测试过,我是根据我的经验写的。 我希望它有效并且易于理解。

【讨论】:

【参考方案4】:

您的代码不起作用,因为第一个条件向下转换失败。

types 的值是 [Dictionary&lt;String, Any&gt;](注意 JSON 中的嵌套字典)而不是 [Dictionary&lt;String, String&gt;]

所以基本上这行得通

 if let types = dict["types"] as? [Dictionary<String, Any>] , types.count > 0 
    if let type = types[0]["type"] as? Dictionary<String, String> 
       if let name = type["name"] 
          self._type = name.capitalized
       
    
    print("TypeAA: \(self._type)")
  else 
    self._type = ""
 

但是厄运金字塔很麻烦,从不.count &gt; 0检查空数组,这样效率更高

 if let types = dict["types"] as? [Dictionary<String, Any>], 
    let firstType = types.first, let typeInfo = firstType["type"] as? Dictionary<String, String>,
    let name = typeInfo["name"] 
       self._type = name.capitalized
       print("TypeAA:", self._type)
  else 
    self._type = ""
 

如果您需要考虑所有名称,则必须使用循环

 if let types = dict["types"] as? [Dictionary<String, Any>] 
    for type in types 
        if let typeInfo = type["type"] as? Dictionary<String, String>,
           let name = typeInfo["name"] 
           print("TypeAA:", name)
        
   
  else 
    self._type = ""
 

如果你想打印所有的名字,用逗号分隔

if let types = dict["types"] as? [Dictionary<String, Any>] 
    let names = types.compactMap  type -> String? in
        guard let typeInfo = type["type"] as? Dictionary<String, String>,
            let name = typeInfo["name"] else  return nil 
        return name
    
    print(names.joined(separator: ", "))

【讨论】:

#Vadian,您的解决方案很容易理解并且有效。这对我很有帮助。非常感谢。 对不起,我还是一头雾水。 对不起,我还是一头雾水。我使用你的循环代码,但似乎只有一种类型被正确获取。控制台日志如下所示。 TypeAA:毒 TypeAA:bug 到这里了吗? 2018-11-25 18:27:20.067718+0700 PokeMum[11401:1131765] TIC 读取状态 [1:0x0]: 1:57 2018-11-25 18:27:20.067883+0700 PokeMum[11401:1131765] TIC 读取Status [1:0x0]: 1:57 而我的预期是打印出来:“Poison/Grass”(2 种),如何执行? 在给定的 JSON 中没有字符串 bug。而TypeAA: poison / TypeAA: bug 是 2 种类型。每种类型都单独打印。 谢谢@vadian,还有一个问题,在使用循环代码时,如何打印出这样的字符串:“Poison/Grass”。我是新手,请多多指教。

以上是关于如何解析这个 JSON 口袋妖怪字典?口袋妖怪 API (swift 3)的主要内容,如果未能解决你的问题,请参考以下文章

SwiftyJSON 代码 - 为啥/如何工作?

如何在节点 js 中解析 PokeAPI [Object] 和 [Array]

循环不会迭代所有JSON数据集

无法进入 json 导致打字稿反应

口袋妖怪叶子绿捉怪金手指

《口袋妖怪 太阳/月亮》正式公布 简体中文确认