如何在 swift 4.1 和 xcode 9.3 中使用 JSONDecoder 解码嵌套的 JSON 数组和对象?

Posted

技术标签:

【中文标题】如何在 swift 4.1 和 xcode 9.3 中使用 JSONDecoder 解码嵌套的 JSON 数组和对象?【英文标题】:How to decode nested JSON array and object with JSONDecoder in swift 4.1 and xcode 9.3? 【发布时间】:2018-05-17 05:23:19 【问题描述】:

我是 iOS 新手,我在解码包含许多嵌套数组和对象的嵌套 JSON 文件时遇到问题。我正在使用 JSONDecoder 进行解码,但在某处我出错或解码不正确。

我的解码器是

let myOrder = try JSONDecoder().decode(MyOrder.self, from: data!)
                    for items in myOrder.OrderDetials 
                        self.orders.append(MyOrders(order_id: items.order_id!, order_ref_number: items.order_ref_number!, cust_mob: items.cust_mob!, store_name: items.store_name!, store_id: items.store_id!, order_details: items.order_details!, order_amount: items.order_amount!, order_status: items.order_status!, order_status_remark: items.order_status_remark!, order_place_at: items.order_place_at!, order_status_change_at: items.order_status_change_at!))
                        print(items.cust_mob!)
                    
                    print(myOrder)

它抛出的错误是

typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "OrderDetials", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "order_details", intValue: nil)], debugDescription: "Expected to decode Array<Any> but found a string/data instead.", underlyingError: nil))

我的结构是

struct MyOrder: Decodable 
    var OrderDetials: [OrderDetails]


struct OrderDetails: Decodable 
    var order_id: String?
    var order_ref_number: String?
    var cust_mob: String?
    var store_name: String?
    var store_id: String?
    var order_details: OrderItems?
    var order_amount: String?
    var order_status: String?
    var order_status_remark: String?
    var order_place_at: String?
    var order_status_change_at: String?



struct OrderItems: Decodable 
    var allorder: [AllOrder]
    var TaxDetials: [TaxDetails]


    struct AllOrder: Decodable 
        var date_time: String?
        var item: String?
        var name: String?
    
    struct TaxDetails: Decodable 
        var tax_per: String?
        var tax_name: String?
    


和DataModel类

class MyOrders 
    var order_id: String
    var order_ref_number: String
    var cust_mob: String
    var store_name: String
    var store_id: String
    var order_details: OrderItems?
    var order_amount: String
    var order_status: String
    var order_status_remark: String
    var order_place_at: String
    var order_status_change_at: String?

    init(order_id: String, order_ref_number: String, cust_mob: String, store_name: String, store_id: String, order_details: OrderItems?, order_amount: String, order_status: String, order_status_remark: String, order_place_at: String, order_status_change_at: String?) 
        self.order_id = order_id
        self.order_ref_number = order_ref_number
        self.cust_mob = cust_mob
        self.store_name = store_name
        self.store_id = store_id
        self.order_details = order_details
        self.order_amount = order_amount
        self.order_status = order_status
        self.order_status_remark = order_status_remark
        self.order_place_at = order_place_at
        self.order_status_change_at = order_status_change_at
    


class MyItems 
    var item: String
    var name: String
    var price: String

    init(item: String, name: String, price: String) 
        self.item = item
        self.name = name
        self.price = price
    

我的 JSON 是


    "OrderDetials": [
        
            "order_id": "11",
            "order_ref_number": "MM1525235813",
            "cust_mob": "9958324531",
            "store_name": "Moti mahal",
            "store_id": "1",
            "order_details": "'allorder':[\"date_time\":\"\",\"item\":\"2\",\"name\":\"CHICKN ROLL\",\"price\":\"360\"]\"TaxDetials\":[\"tax_per\":\"5\",\"tax_name\":\"CGST & SGST\"]",
            "order_amount": "378.0",
            "order_status": "1",
            "order_status_remark": "New_Order_Place",
            "order_place_at": "2018-05-02 10:06:53",
            "order_status_change_at": null
        
    ]

请有人告诉我如何正确解码或我需要对结构进行哪些更改。

【问题讨论】:

您的“order_details”键的值是字符串,您的结构将其视为数组。您必须根据定义的结构更改“order_details”键的值才能使其工作 您的 order_details 包含 JSON 之类的结构而不是字符串 我试过这样做:“var order_details: String?”还有这个:“var order_details:[OrderItems]?”两者都给出相同的错误。 @Vikky var order_details: 字符串?正在工作 查看这篇文章,它解释得很好medium.com/@nimjea/json-parsing-in-swift-2498099b78f 【参考方案1】:

OrderDetialsArray of Dictionary [[String: String?]] ,而您的 Initial 响应是 Dictionary 也是 order_detailsWrong json String 而不是 Dictionary ,所以我们将它解析为字符串,在 Codable 每个字典 @ 987654329@ 转换为StructClass[]Array

型号:

import Foundation

struct Initial: Codable 
    let orderDetials: [OrderDetial]

    enum CodingKeys: String, CodingKey 
        case orderDetials = "OrderDetials"
    


struct OrderDetial: Codable 
    let orderID, orderRefNumber, custMob, storeName: String
    let storeID, orderDetails, orderAmount, orderStatus: String
    let orderStatusRemark, orderPlaceAt: String
    let orderStatusShangeAt:String?

    enum CodingKeys: String, CodingKey 
        case orderID = "order_id"
        case orderRefNumber = "order_ref_number"
        case custMob = "cust_mob"
        case storeName = "store_name"
        case storeID = "store_id"
        case orderDetails = "order_details"
        case orderAmount = "order_amount"
        case orderStatus = "order_status"
        case orderStatusRemark = "order_status_remark"
        case orderPlaceAt = "order_place_at"
        case orderStatusShangeAt = "order_status_change_at"


    



// MARK: Convenience initializers

extension Initial 
    init(data: Data) throws 
        self = try JSONDecoder().decode(Initial.self, from: data)
    

这样使用:

   if  let initial =  try? Initial.init(data: data)

                for item in initial.orderDetials 
                    print(item.orderAmount)
                    print(item.orderDetails) // here is Wrong format from your Server API
                
           

Order_details 错误

'allorder':["date_time":"","item":"2","name":"CHICKN ROLL","price":"360"]"TaxDetials":["tax_per":"5","tax_name":"CGST & SGST"]

【讨论】:

现在我得到了 orderDetails 作为字符串。我需要使用 JSONSerialization 来访问其中的数据还是 JSONDecoder 会自动执行此操作? 是的,你可以再次解析它,但它也错误地检查了这个'allorder'不是“allorder” 谢谢,实际上 JSON 是由 API 团队生成的,android 团队也使用相同的 JSON 并且它在那里工作,所以我必须使用相同的 JSON。 不,和服务器上的一样。我已经仔细检查了。 好的,所以你的后端开发人员错了,你可以和你的android开发人员核实一下,他可能用任何其他方式格式化这个字符串,但是这个错误的Json和错误的json字符串

以上是关于如何在 swift 4.1 和 xcode 9.3 中使用 JSONDecoder 解码嵌套的 JSON 数组和对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Xcode 9.3 中切换到 Swift 4.0?

Xcode 9.3(Swift 4.1)中的 Codable '没有初始化器'

Xcode 9.3 编译 Swift 源项目永远不会完成

Swift 自动布局在 Xcode 9.3 中不起作用

Xcode 9.3 新增能力,优化 Swift 编译生成代码的尺寸

堆栈视图中的自动约束冲突、Swift 2、iOS 9.3、XCode 7