【问题标题】:How can I parse this JSON Pokemon Dictionary? Pokemon API (swift 3)如何解析这个 JSON 口袋妖怪字典?口袋妖怪 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,但请就这些代码提出建议。

标签: ios json swift parsing


【解决方案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”。我是新手,请多多指教。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      • 1970-01-01
      • 2020-06-10
      • 2021-11-07
      • 2021-01-19
      • 2016-12-30
      相关资源
      最近更新 更多