簡體   English   中英

將 JSON 解碼為可編碼對象 - 有條件

[英]Decoding JSON into Codable Objects - with condition

我想使用 Codable 協議將 JSON 解碼為對象。

我想要達到的結果是:

[
 [ 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",
            }
         ]
      }
  ]

如您所見,集合的類型為 item 或 location。 數據將根據該類型。 我應該如何使用 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
    }
}

如何使用適當的對象傳播數據?

我建議兩種方法:

方法一

更改數據結構以消除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

方法二

如果無法更改 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)
        }
    }
}

兩種方法的優缺點:

方法一

優點:使數據更具自我描述性

缺點:允許既沒有items也沒有locations的集合

方法二

優點:適用於現有的數據結構

缺點:將允許部分Location和部分Itemdata數組

除非您的真實代碼有更多內容,否則您似乎完全按照默認值定義CodingKeys ,因此您可以將其刪除。

與其使用條件解析,我建議您可以使用具有多個屬性和可選值的公共類,並根據需要使用它。 請參考以下代碼。

例如,如果itemTitlenil則執行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
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM