为啥我的 json 响应对象返回 nil?

Posted

技术标签:

【中文标题】为啥我的 json 响应对象返回 nil?【英文标题】:Why are my json response objects returning nil?为什么我的 json 响应对象返回 nil? 【发布时间】:2020-06-11 04:52:29 【问题描述】:

我有一些 json:

   
   "wallets":[
      
         "fundingProviderName":"tns_cof",
         "authLimit":75,
         "pinRequired":true,
         "wallets":[
            
               "authLimit":75,
               "isCardSupported":true,
               "paymentProcessorId":6,
               "mainDisplayText":"...0013",
               "imageUrl":"https://az755244.vo.msecnd.net/paymentimages/visa2.png",
               "userPaymentSourceId":9756,
               "secondaryDisplayText":"12/30",
               "expDate":"2030-12-31T23:59:59Z",
               "cardIssuer":"Visa"
            ,
            
               "authLimit":75,
               "isCardSupported":true,
               "paymentProcessorId":7,
               "mainDisplayText":"...1020",
               "imageUrl":"https://az755244.vo.msecnd.net/paymentimages/mastercard2.png",
               "userPaymentSourceId":9757,
               "secondaryDisplayText":"12/25",
               "expDate":"2025-12-31T23:59:59Z",
               "cardIssuer":"Mastercard"
            ,
            
               "authLimit":75,
               "isCardSupported":true,
               "paymentProcessorId":8,
               "mainDisplayText":"...3025",
               "imageUrl":"https://az755244.vo.msecnd.net/paymentimages/amex.png",
               "userPaymentSourceId":9758,
               "secondaryDisplayText":"12/27",
               "expDate":"2027-12-31T23:59:59Z",
               "cardIssuer":"Amex"
            
         ],
         "isSupported":true
      
   ]

我的结构是这样的:

struct CreditCard: Codable 
    var authLimit: Int?
    var isCardSupported: Bool?
    var paymentProcessorId: Int?
    var mainDisplayText: String?
    var imageUrl: String?
    var userPaymentSourceId: Int?
    var secondaryDisplayText: String?
    var expDate: String?
    var cardIssuer: String?

    enum CodingKeys: String, CodingKey 
        case cardIssuer = "cardIssuer"
        case authLimit = "authLimit"
        case isCardSupported = "isCardSupported"
        case paymentProcessorId = "paymentProcessorId"
        case mainDisplayText = "mainDisplayText"
        case imageUrl = "imageUrl"
        case userPaymentSourceId = "userPaymentSourceId"
        case secondaryDisplayText = "secondaryDisplayText"
        case expDate = "expDate"
    

    init(from decoder: Decoder) throws 
        let values = try decoder.container(keyedBy: CodingKeys.self)
        authLimit = try values.decodeIfPresent(Int.self, forKey: .authLimit)
        isCardSupported = try values.decodeIfPresent(Bool.self, forKey: .isCardSupported)
        paymentProcessorId = try values.decodeIfPresent(Int.self, forKey: .paymentProcessorId)
        mainDisplayText = try values.decodeIfPresent(String.self, forKey: .mainDisplayText)
        imageUrl = try values.decodeIfPresent(String.self, forKey: .imageUrl)
        userPaymentSourceId = try values.decodeIfPresent(Int.self, forKey: .userPaymentSourceId)
        secondaryDisplayText = try values.decodeIfPresent(String.self, forKey: .secondaryDisplayText)
        expDate = try values.decodeIfPresent(String.self, forKey: .expDate)
        cardIssuer = try values.decodeIfPresent(String.self, forKey: .cardIssuer)
    

我的 json 解码器代码如下所示:

do 
if let jsonData = response?.responseData 
let jsonDecoder = JSONDecoder()
let creditCards = try jsonDecoder.decode(CreditCard.self, from: jsonData)
print("credit cards \(creditCards)")
completion(nil, creditCards)

 catch 
print(error)

我敢肯定,为什么模型仍然为零,这可能是一个明显的疏忽。任何帮助将非常感激。谢谢!

【问题讨论】:

您必须始终从顶部解码 JSON。因此,两个带有键 wallets 的对象(顺便说一下是数组)都丢失了。而且你不需要所有的样板初始化代码。字典清楚地总是包含所有键。 您的 Codable 中缺少***密钥 "wallets":,请检查并更新 你可以按照这个教程youtube.com/watch?v=cyWrj61vpCY我想这对你有帮助! 【参考方案1】:

要么从 JSON 顶部解码(正如@Rob 回答的那样),要么遍历 JSON 并获取 wallets 密钥,然后对其进行解码。

if let jsonData = response?.responseData as? Dictionary<String,Any> 
    if let walletData = jsonData["wallet"] as? [Dictionary<String,Any>] 
        if let mainWalletData = walletData[0]["wallets"] as? [Dictionary<String,Any>] 
            do 
                let jsonDecoder = JSONDecoder()
                let creditCards = try jsonDecoder.decode([CreditCard].self, from: mainWalletData)
                print("credit cards \(creditCards)")
                completion(nil, creditCards)
            
         catch 
            print(error)
        
    


【讨论】:

【参考方案2】:
struct Wallet: Decodable 
 let wallets: [WalletDetails]

struct WalletDetails: Decodable 
 let fundingProviderName: String
 let authLimit: Int
 let pinRequired: Bool
 let wallets: [CreditCard]

struct CreditCard: Codable 
var authLimit: Int?
var isCardSupported: Bool?
var paymentProcessorId: Int?
var mainDisplayText: String?
var imageUrl: String?
var userPaymentSourceId: Int?
var secondaryDisplayText: String?
var expDate: String?
var cardIssuer: String?

enum CodingKeys: String, CodingKey 
    case cardIssuer = "cardIssuer"
    case authLimit = "authLimit"
    case isCardSupported = "isCardSupported"
    case paymentProcessorId = "paymentProcessorId"
    case mainDisplayText = "mainDisplayText"
    case imageUrl = "imageUrl"
    case userPaymentSourceId = "userPaymentSourceId"
    case secondaryDisplayText = "secondaryDisplayText"
    case expDate = "expDate"


init(from decoder: Decoder) throws 
    let values = try decoder.container(keyedBy: CodingKeys.self)
    authLimit = try values.decodeIfPresent(Int.self, forKey: .authLimit)
    isCardSupported = try values.decodeIfPresent(Bool.self, forKey: .isCardSupported)
    paymentProcessorId = try values.decodeIfPresent(Int.self, forKey: .paymentProcessorId)
    mainDisplayText = try values.decodeIfPresent(String.self, forKey: .mainDisplayText)
    imageUrl = try values.decodeIfPresent(String.self, forKey: .imageUrl)
    userPaymentSourceId = try values.decodeIfPresent(Int.self, forKey: .userPaymentSourceId)
    secondaryDisplayText = try values.decodeIfPresent(String.self, forKey: .secondaryDisplayText)
    expDate = try values.decodeIfPresent(String.self, forKey: .expDate)
    cardIssuer = try values.decodeIfPresent(String.self, forKey: .cardIssuer)


您没有添加***密钥,这就是它不起作用的原因。试试这个:

 do 
    if let jsonData = response?.responseData 
    let jsonDecoder = JSONDecoder()
    let creditCards = try jsonDecoder.decode(Wallet.self, from: jsonData)
    print("credit cards \(creditCards)")
    completion(nil, creditCards)
    
     catch 
    print(error)
    

【讨论】:

【参考方案3】:

您的 Codable 中缺少***密钥 wallets,您无需实现 init(from decoder: Decoder) throws

【讨论】:

以上是关于为啥我的 json 响应对象返回 nil?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 tableView 变量返回 nil?

将 alamofire 响应解析为 JSON 返回 nil

为啥我不能用我的 api 响应更新我的状态?数据是一个对象数组

为啥在测试 RSPEC 时 JBuilder 不返回 JSON 中的响应正文

为啥从 django rest 框架返回的 JSON 在响应中有正斜杠?

为啥我的 JSON 响应在 forEach 上崩溃? TypeError 未定义