[英]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
和部分Item
的data
數組
除非您的真實代碼有更多內容,否則您似乎完全按照默認值定義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
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.