You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Alamofire调用CoinMarketCap API时数据解码失败求助

解决CoinMarketCap API数据解码失败问题

错误原因分析

你遇到的解码错误明确指向类型不匹配:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

核心问题是:JSON返回的data字段是数组类型(加密货币列表),但你的模型解析逻辑期望将其解析为单个字典对象,导致结构不匹配。


具体修复步骤

1. 修正模型层级的重复解析问题

你的ResponseObjectModel与BaseResponseModel存在重复处理data字段的冲突:

  • BaseResponseModel已经定义了data: [CurrencyResponse?],对应JSON的数组结构
  • ResponseObjectModel又尝试将data映射为泛型T,而你请求时传入的T是单个CurrencyResponse对象,与实际数组类型不匹配

修复方案:简化请求解码逻辑
修改RequestManager的request方法,直接用BaseResponseModel作为顶层解析模型,移除ResponseObjectModel的冗余包装:

static func request(_ request: RequestDelegate, success: @escaping ObjectClosure<BaseResponseModel>, failure: @escaping ErrorClosure) {
    let request = createRequest(request)
    
    request.responseData { (response) in
        switch response.result {
        case .success:
            debugPrint("REQUEST: \(response.request)")
            guard let data = response.data else {
                handleFailure(response: response, failure: failure)
                return
            }
            do {
                let model = try JSONDecoder().decode(BaseResponseModel.self, from: data)
                success(model)
            } catch {
                print("解码失败: \(error)")
                handleFailure(response: response, failure: failure)
            }
        case .failure:
            handleFailure(response: response, failure: failure)
        }
    }
}

2. 调整ViewModel的数据类型

ViewModel中存储数据的变量需要匹配数组类型:

final class AllCurrenciesViewModel: AllCurrenciesViewModelProtocol {
    public var didSuccess: ()->() = {}
    public var didFailure: (String)->() = {_ in}
    
    private var currenciesData: [CurrencyResponse]? // 改为数组类型
    
    func requestAllCurrencies() {
        LastestCurrenciesRequest(start: 1, limit: 1, sort: "market_cap", currencyType: "all").request { [weak self] response in
            guard let self = self, let responseModel = response else { return }
            // 过滤数组中的nil元素
            self.currenciesData = responseModel.data.compactMap { $0 }
            self.didSuccess()
        } failure: { (error) in
            self.didFailure(error.message ?? "")
        }
    }
}

3. 修复CurrencyResponse的字段错误

你的模型中有一个拼写错误:queto应该对应JSON中的quote字段,同时补充完整的字段映射和关联模型:

struct CurrencyResponse: Codable {
    var id: Int?
    var name: String?
    var symbol: String?
    var slug: String?
    var cmcRank: Int?
    var numMarketPairs: Int?
    var circulatingSupply: Int?
    var totalSupply: Int?
    var maxSupply: Int?
    var quote: Quote? // 修正拼写错误
    var lastUpdated: String?
    var dateAdded: String?
    var tags: [String?]
    
    // 明确定义字段映射关系
    enum CodingKeys: String, CodingKey {
        case id, name, symbol, slug
        case cmcRank = "cmc_rank"
        case numMarketPairs = "num_market_pairs"
        case circulatingSupply = "circulating_supply"
        case totalSupply = "total_supply"
        case maxSupply = "max_supply"
        case quote
        case lastUpdated = "last_updated"
        case dateAdded = "date_added"
        case tags
    }
}

// 补充Quote关联模型
struct Quote: Codable {
    var usd: QuoteDetail?
    
    enum CodingKeys: String, CodingKey {
        case usd = "USD"
    }
}

struct QuoteDetail: Codable {
    var price: Double?
    var volume24h: Double?
    var volumeChange24h: Double?
    var percentChange1h: Double?
    var percentChange24h: Double?
    var percentChange7d: Double?
    var percentChange30d: Double?
    var percentChange60d: Double?
    var percentChange90d: Double?
    var marketCap: Double?
    var marketCapDominance: Double?
    var fullyDilutedMarketCap: Double?
    var lastUpdated: String?
    
    enum CodingKeys: String, CodingKey {
        case price
        case volume24h = "volume_24h"
        case volumeChange24h = "volume_change_24h"
        case percentChange1h = "percent_change_1h"
        case percentChange24h = "percent_change_24h"
        case percentChange7d = "percent_change_7d"
        case percentChange30d = "percent_change_30d"
        case percentChange60d = "percent_change_60d"
        case percentChange90d = "percent_change_90d"
        case marketCap = "market_cap"
        case marketCapDominance = "market_cap_dominance"
        case fullyDilutedMarketCap = "fully_diluted_market_cap"
        case lastUpdated = "last_updated"
    }
}

4. 简化BaseResponseModel

移除自定义初始化逻辑,让Codable自动生成解码代码:

class BaseResponseModel: Codable {
    var status: CurrencyStatus?
    var data: [CurrencyResponse?]
    
    enum CodingKeys: String, CodingKey {
        case status, data
    }
}

内容的提问来源于stack exchange,提问作者Bedri Doğan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:28:16