使用可解码的代码捕获单行嵌套对象的数组

问题描述 投票:0回答:3

下面是我的json响应和结构格式,需要在其中进行收缩我也不想创建除Response,Media之外的任何其他结构,并想按如下所示在单行中进行解析。

{
     "name": "xxxx",
     "title": "xxxxxxx",
     "assets": [
        {
          "items": [
            {
              "id": "eeee",
              "desc": "rrrrrr"
            },            {
              "id": "eeee",
            },            {
              "desc": "rrrrrr"
            }]
        }]
}



struct Response {
     name  : String
     title : string
     items : [Media]

    private enum codingKeys : String, CodingKey {
        case name = "name"
        case title = "title"
        case items = "assets.items"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: codingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        title = try container.decode(TrayLayout.self, forKey: .title)
        items = try container.decode([Media].self, forKey: .items)
    }
  }
ios arrays json nested codable
3个回答
0
投票

您可以尝试以下方法:

struct Response: Decodable {
  let name, title: String
  let assets: [Assets]
}

struct Assets: Decodable {
 let items: [Items]
}

struct Items: Decodable {
  let id, desc: String
}

然后您可以像这样解码它:

guard let response = try? JSONDecoder().decode(Response.self, from: data) else { print("Response not parsed"); return }

0
投票

如果要跳过assets级别,则必须将items声明为嵌套数组[[Media]],并使用嵌套容器进行解码。但是我不知道[.customDecodingStrategy

的目标是什么
struct Response : Decodable {
    let name  : String
    let title : String
    let items : [[Media]]

    private enum CodingKeys : String, CodingKey { case name, title, assets }
    private enum ItemsCodingKeys : String, CodingKey { case items }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        title = try container.decode(String.self, forKey: .title)
        var assetsContainer = try container.nestedUnkeyedContainer(forKey: .assets)
        var itemData = [[Media]]()
        while !assetsContainer.isAtEnd {
            let itemsContainer = try assetsContainer.nestedContainer(keyedBy: ItemsCodingKeys.self)
            itemData.append(try itemsContainer.decode([Media].self, forKey: .items))
        }
        items = itemData
    }
}

struct Media : Decodable {
    let id, desc : String?
}

0
投票

我设法找到您问题的解决方案。

考虑以下是示例json

let jsonString = """
{
     "name": "xxxx",
     "title": "xxxxxxx",
     "assets": [
        {
          "items": [
            {
              "id": "id11",
              "desc": "desc11"
            },            {
              "id": "id12",
            },            {
              "desc": "desc13"
            }]
        },{
          "items": [
            {
              "id": "id21",
              "desc": "desc21"
            },            {
              "id": "id22",
            },            {
              "desc": "desc23"
            }]
        }]
}
"""

您的结构将如下所示

struct Media: Codable {
    let id,desc: String?
    enum CodingKeys: String, CodingKey {
        case id,desc
    }
}

struct Response: Decodable {
    let name,title: String?
    let items: [Media]?
    enum CodingKeys: String, CodingKey {
        case name,title,items
        case assets = "assets"
    }
    // Decoding
    init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        title = try container.decode(String.self, forKey: .title)

        // Here as the assets contains array of object which has a key as items and then again consist of a array of Media we need to decode as below
        let assets = try container.decode([[String:[Media]]].self, forKey: .assets)

        // At this stage will get assets with a array of array so we first map and retrive the items and then reduce them to one single array
        items = assets.compactMap{$0[CodingKeys.items.rawValue]}.reduce([], +)
    }
}

最后是时候按以下方式使用它了

let data = jsonString.data(using: .utf8)!
let myResponse = try! JSONDecoder().decode(Response.self, from: data)

现在您可以按以下方式访问数据

myResponse.name
myResponse.title
myResponse.items

希望此基本代码可以帮助您实现想要的工作。然后,您可以继续进行更多的嵌套解析。

我想感谢Nic Laughtersuch a detailed article;通过参考我设法提供了上述解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.