【问题标题】: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我想这对你有帮助!

标签: ios json swift xcode codable


【解决方案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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-05
        • 1970-01-01
        • 2014-06-02
        • 2019-06-30
        相关资源
        最近更新 更多