将 JSON 解码为可编码对象 - 有条件
Decoding JSON into Codable Objects - with condition
我想将 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
}
}
如何使用适当的对象传播数据?
我建议您可以使用具有多个属性和可选值的公共 class,而不是使用条件解析,并根据需要使用它。请参考以下代码。
例如如果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
}
}
我建议两种方法:
方法一
更改您的数据结构以消除 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 更改为:
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)
}
}
}
两种方法的优缺点:
方法一
专业版:让数据更多self-descriptive
缺点:允许集合既没有 items
也没有 locations
方法二
专业版:适用于现有数据结构
缺点:将允许 data
数组部分为 Location
部分为 Item
除非您的实际代码有更多内容,否则您似乎将 CodingKeys
定义为与默认值完全相同,因此您可以删除它。
我想将 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
}
}
如何使用适当的对象传播数据?
我建议您可以使用具有多个属性和可选值的公共 class,而不是使用条件解析,并根据需要使用它。请参考以下代码。
例如如果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
}
}
我建议两种方法:
方法一
更改您的数据结构以消除 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 更改为:
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)
}
}
}
两种方法的优缺点:
方法一
专业版:让数据更多self-descriptive
缺点:允许集合既没有 items
也没有 locations
方法二
专业版:适用于现有数据结构
缺点:将允许 data
数组部分为 Location
部分为 Item
除非您的实际代码有更多内容,否则您似乎将 CodingKeys
定义为与默认值完全相同,因此您可以删除它。