预期解码 Array<Any> 但找到了字典

Posted

技术标签:

【中文标题】预期解码 Array<Any> 但找到了字典【英文标题】:Expected to decode Array<Any> but found a dictionary instead 【发布时间】:2017-12-28 12:14:49 【问题描述】:

我从返回数组的 API 获取数据,但需要用具有“子级别”的 API 替换它:

RAW:
    ETH:
        USD:
             TYPE:              "5"
             MARKET:            "CCCAGG"
             FROMSYMBOL:        "ETH"
             TOSYMBOL:          "USD"
             PRICE:             680.89
             CHANGEPCT24HOUR    :   -9.313816893529749

这是我的结构:

struct Ethereum: Codable 

    let percentChange24h: String
    let priceUSD: String

    private enum CodingKeys: String, CodingKey 
        case priceUSD = "PRICE", percentChange24h = "CHANGEPCT24HOUR"
    

以及实现:

    func fetchEthereumInfo(completion: @escaping (Ethereum?, Error?) -> Void) 
    let url = URL(string: "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD")!

    let task = URLSession.shared.dataTask(with: url)  (data, response, error) in
        guard let data = data else  return 
        do 
            if let ethereumUSD = try JSONDecoder().decode([Ethereum].self, from: data).first 
                print(ethereumUSD)
                completion(ethereumUSD, nil)
            
         catch 
            print(error)
        
    
    task.resume()

控制台打印typeMismatch(Swift.Array&lt;Any&gt;, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array&lt;Any&gt; but found a dictionary instead.", underlyingError: nil))

我真的不知道要在我的代码中更新什么或这种形式的 API 是什么

【问题讨论】:

【参考方案1】:

首先 JSON 不包含任何数组。阅读 JSON 非常容易。只有 2(两个!)集合类型,数组 [] 和字典 。如您所见,JSON 字符串中根本没有方括号。

任何(子)字典 都必须解码为自己的类型,所以它应该是

struct Root : Decodable 
    private enum CodingKeys : String, CodingKey  case raw = "RAW" 
    let raw : RAW


struct RAW : Decodable 
    private enum CodingKeys : String, CodingKey  case eth = "ETH" 
    let eth : ETH


struct ETH : Decodable 
    private enum CodingKeys : String, CodingKey  case usd = "USD" 
    let usd : USD


struct USD : Decodable 

    private enum CodingKeys : String, CodingKey 
        case type = "TYPE"
        case market = "MARKET"
        case price = "PRICE"
        case percentChange24h = "CHANGEPCT24HOUR"
    
    let type : String
    let market : String
    let price : Double
    let percentChange24h : Double

要解码 JSON 并打印 percentChange24h,您必须编写

 let result = try JSONDecoder().decode(Root.self, from: data)
 print("percentChange24h", result.raw.eth.usd.percentChange24h)

【讨论】:

非常感谢瓦迪安!这正是我一直在寻找的。 result.raw.eth.usd.percentChange24h 有更简单的语法吗? 你可以在Root中声明一个计算变量来得到raw.eth.usd 太好了,顺便说一句,我在let result 线上收到了Initializer for conditional binding must have Optional type, not 'Root'。我想保留我的 do-catch 方法,那么我该如何摆脱错误? 不要if let,如果解码成功则结果是非可选的 别忘了告诉 OP 在 catch 内和守卫 else 括号内调用完成 completion(nil, error)

以上是关于预期解码 Array<Any> 但找到了字典的主要内容,如果未能解决你的问题,请参考以下文章

debugDescription:“预期解码 Array<Any>,但找到了字典。”,underlyingError:nil)

Swift 4 JSON Parsing(预期解码 Array<Any> 但找到了字典)

解析 JSON 错误“预期解码 Array<Any> 但找到了一个数字

预期解码 Dictionary<String, Any> 但找到一个数组而不是 JSON SwiftUI

JSONDecoder - “预期解码 Dictionary<String, Any> 但找到了一个字符串/数据。”

类型不匹配。预期解码 Dictionary<String, Any> 但找到了一个数组