获取 API 时解码失败 |迅速

Posted

技术标签:

【中文标题】获取 API 时解码失败 |迅速【英文标题】:Decoding failed while fetching API | Swift 【发布时间】:2021-07-23 23:55:40 【问题描述】:

当我打印 self.getTokenBalancesModel 时,它给了我解码失败的错误。我做错了什么?

视图模型

import Foundation
import Alamofire

final class TokenBalancesClassAViewModel: ObservableObject 
    
    @Published var getTokenBalancesModel: [GetTokenBalancesItemsModel] = [GetTokenBalancesItemsModel]()
    
    func makeApiRequest() 
        let url = "https://api.covalenthq.com/v1/1/address/0x726A73081C4134b2f639b821377482c71864EBc8/balances_v2/?&key=ckey_4eeea29a22c14701a9844f01151"
        
        AF.request(url).responseData(completionHandler:  data in
            if let apiJsonData = try? JSONDecoder().decode(TokenBalancesModel.self, from: data.data!)
                self.getTokenBalancesModel = apiJsonData.data.items
                print(self.getTokenBalancesModel)
             else 
                print("Decoding failed")
            
        )
    

模型

struct TokenBalancesModel: Codable, Hashable 
    let data: TokenBalancesDataModel
    let error: Bool


struct TokenBalancesDataModel: Codable, Hashable 
    let address: String
    let quote_currency: String
    let items: [TokenBalancesItemsModel]


struct TokenBalancesItemsModel: Codable, Hashable 
    let contract_name: String
    let contract_ticker_symbol: String
//    let logo_url: String
    let balance: Int
    let quote_rate: Float
    let quote: Float

很明显在解码部分:

if let apiJsonData = try? JSONDecoder().decode(TokenBalancesModel.self, from: data.data!)

我在哪里犯了错误,但我不明白为什么

【问题讨论】:

您可以使用responseDecodable直接解码您的类型,无需手动进行。 什么意思?你能写一个例子吗? @JonShier 不要使用responseData,而是使用responseDecodable @JonShier 如果替换它,它会说:Generic parameter 'T' could not be inferred 是的,你需要真正正确地使用它。在您的情况下,responseDecodable(of: TokenBalancesModel.self) 或类似名称。您可以在文档中阅读更多内容。 【参考方案1】:

如果您发现错误,您将获得更多信息而不是try?

在调试常见的 catch 链时,我将使用 is

 catch let DecodingError.dataCorrupted(context) 
    print(context)
 catch let DecodingError.keyNotFound(key, context) 
    print("Key '\(key)' not found:", context.debugDescription)
    print("codingPath:", context.codingPath)
 catch let DecodingError.valueNotFound(value, context) 
    print("Value '\(value)' not found:", context.debugDescription)
    print("codingPath:", context.codingPath)
 catch let DecodingError.typeMismatch(type, context) 
    print("Type '\(type)' mismatch:", context.debugDescription)
    print("codingPath:", context.codingPath)
 catch 
    print("error: ", error)

使用上面你会看到如下错误

类型“Int”不匹配:应解码 Int,但找到了字符串/数据。 codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "items", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "balance" , intValue: nil)]

这会引起您注意 TokenBalancesItemsModel.balance 字段的类型不正确。

【讨论】:

jojojo调试到另一个lvl 谢谢!我将从现在开始实现这个:) 这也很奇怪,在文档中他们将它作为整数 hm.. 无论如何,非常感谢! 根据我自己的个人经验,我发现有时 API 会将它们指定的类型返回为不同的类型,我有许多 bool 值作为整数或字符串,或字符串中的整数。更糟糕的是,API 会为不同的实体返回不同的类型。不幸的是,这只是意味着我们必须将其转换为我们在客户端中想要的方式。 我在 Playgrounds 中进行了测试,但这里有一个 Gist 示例解决方案,用于将字符串解码为 int,而无需手动为您的类型编写整个解码 init。 gist.github.com/theoriginalbit/2b184d4e94ed3d46e5048e769b0b196b 编辑:我看到你删除了你的信息,希望这意味着你解决了?【参考方案2】:

使用这个,注意选项:

struct TokenBalancesModel: Codable, Hashable 
    let data: TokenBalancesDataModel
    let error: Bool


struct TokenBalancesDataModel: Codable, Hashable 
    let address: String?
    let quote_currency: String?
    let items: [TokenBalancesItemsModel]


struct TokenBalancesItemsModel: Codable, Hashable 
    let contract_name: String?
    let contract_ticker_symbol: String?
//    let logo_url: String
    let balance:  String?    // <-- here no Int
    let quote_rate: Float?
    let quote: Float?

【讨论】:

如果值是数字(int),为什么是可选的字符串? 余额不是一个数字,它是一个字符串。如果这对您不起作用,请告诉我。 "balance" : "52315554326750453",是一个字符串,如果是数字,它就是 "balance" : 52315554326750453。不带引号。 是的,这些选项起到了作用,我以后如何打开它?我试过:print(self.getTokenBalancesModel!) 但它抱怨,它说:Cannot force unwrap value of non-optional type '[TokenBalancesItemsModel]' 如您所见:“let items: [TokenBalancesItemsModel]”不是可选的。不要打开它。

以上是关于获取 API 时解码失败 |迅速的主要内容,如果未能解决你的问题,请参考以下文章

如何从两个不同的 api 模拟中获取数据?迅速

访问rest-api方法getAll时获取数据失败[重复]

如何从节点 api 中的获取请求中解码 JWT 令牌

init_fs_encoding:获取文件系统编码的 Python 编解码器失败

币安智能链查询账户余额-解码bech32失败

Gmail API:解码邮件正文(Java/Android)