将 JSON 解码为可编码对象 - 有条件



我想将JSON解码为具有Codable协议的对象。

我想要实现的结果是:

[
 [ Collection
    < collectionType = item
    < collectionName = some name`
    < data = [ Item
                 < itemTitle = title
                 < itemSubtitle = subtitle,
               Item
                 < itemTitle = title
                 < itemSubtitle = subtitle ],
[ Collection
    < collectionType = location
    < collectionName = some name`
    < data = [ Location
                 < locationName = someName,
               Location
                 < locationName = someName ],
[ Collection
    < collectionType = item
    < collectionName = some name`
    < data = [ Item
                 < itemTitle = title
                 < itemSubtitle = subtitle,
               Item
                 < itemTitle = title
                 < itemSubtitle = subtitle ],
[ Collection
    < collectionType = location
    < collectionName = some name`
    < data = [ Location
                 < locationName = someName,
               Location
                 < locationName = someName ]]

JSON如下:

    [{
        "collectionType": "item",
        "collectionName": "some name",
        "data": [
            {
                "itemTitle": "title",
                "itemSubtitle": "subtitle",
            },
            {
                "itemTitle": "title",
                "itemSubtitle": "subtitle",
            }
         ]
      },
      {
        "collectionType": "location",
        "collectionName": "some name",
        "data": [
            {
                "locationName": "a name",
            },
            {
                "locationName": "a name",
            }
         ]
      },
      {
        "collectionType": "item",
        "collectionName": "some name",
        "data": [
            {
                "itemTitle": "title",
                "itemSubtitle": "subtitle",
            },
            {
                "itemTitle": "title",
                "itemSubtitle": "subtitle",
            }
         ]
      },
      {
        "collectionType": "location",
        "collectionName": "some name",
        "data": [
            {
                "locationName": "a name",
            },
            {
                "locationName": "a name",
            }
         ]
      }
  ]

如您所见,集合将是项目或位置类型。数据将根据该类型。我应该如何使用 Codable 实现这一目标?

我的对象如下:

class Collection: NSObject, Codable {
    // MARK: - Properties
    let collectionType: String
    let collectionName: String
    let data????
    // MARK: - Keyes
    private enum CodingKeys: String, CodingKey {
        case collectionType
        case collectionName
    }
}
class Item: NSObject, Codable {
    // MARK: - Properties
    let itemTitle: String
    let itemSubtitle: String
    // MARK: - Keyes
    private enum CodingKeys: String, CodingKey {
        case itemTitle
        case itemSubtitle
    }
}
class Location: NSObject, Codable {
    // MARK: - Properties
    let locationName: String
    // MARK: - Keyes
    private enum CodingKeys: String, CodingKey {
        case locationName
    }
}

如何使用适当的对象传播数据?

我建议两种方法:

方法1

更改数据结构以消除data描述项目还是位置的歧义:

[{
    "collectionName": "some name",
    "items": [
        {
            "itemTitle": "title",
            "itemSubtitle": "subtitle",
        },
        {
            "itemTitle": "title",
            "itemSubtitle": "subtitle",
        }
    ]
},
{
    "collectionName": "some name",
    "locations": [
        {
            "locationName": "a name",
        },
        {
            "locationName": "another name",
        }
    ]
}]

。并修改您的Collection以具有可选的locations和可选的items

方法2

如果更改 JSON 结构不是一种选择,那么我建议将Collection类更改为:

class Collection: Codable {
    let collectionType: String
    let collectionName: String
    let data: [CollectionData]
}

。并创建一个枚举CollectionData

enum CollectionError: Error {
    case invalidData
}
enum CollectionData {
    case item(Item)
    case location(Location)
}
extension CollectionData: Codable {
    init(from decoder: Decoder) throws {
        if let item = try? Item(from: decoder) {
            self = .item(item)
            return
        }
        if let location = try? Location(from: decoder) {
            self = .location(location)
            return
        }
        throw CollectionError.invalidData
    }
    func encode(to encoder: Encoder) throws {
        switch self {
        case .item(let item):
            try item.encode(to: encoder)
        case .location(let location):
            try location.encode(to: encoder)
        }
    }
}

两种方法的优缺点:

方法1

优点:使数据更具自我描述性

缺点:允许既不items也不locations的集合

方法2

优点:适用于现有数据结构

缺点:将允许部分Location和部分Itemdata阵列

除非你的真实代码有更多内容,否则你似乎完全按照默认值定义CodingKeys,所以你可能会删除它。

与其使用条件解析,我建议您可以使用具有可选值的多个属性的公共类,并根据要求使用它。 请参考下面的代码。

例如,如果itemTitle nil则执行locationName逻辑,依此类推。

class Collection: NSObject, Codable {
    let collectionType: String
    let collectionName: String
    let data:data?
    private enum CodingKeys: String, CodingKey {
        case collectionType
        case collectionName
    }
}
class data: NSObject, Codable {
    let itemTitle: String?
    let itemSubtitle: String?
    let locationName: String?
    private enum CodingKeys: String, CodingKey {
        case itemTitle
        case itemSubtitle
        case locationName
    }
}

最新更新