这是基于初始编辑的,它有一些冗余代码,但总体思路应该是可以理解的:
enum Post: Codable {
case post(id: UUID, title: String, ownerId: UUID, ownerType: PostOwner)
case member(id: UUID, firstName: String, lastName: String)
case imageMedium(id: UUID, assetURL: URL, ownerId: UUID, ownerType: ImageOwner)
enum PostType: String, Codable {
case post
case member
case imageMedium = "image-medium"
}
enum PostOwner: String, Codable {
case member
}
enum ImageOwner: String, Codable {
case post
}
enum CodingKeys: String, CodingKey {
case id
case type
case title
case assetUrl = "asset-url"
case ownerId = "owner-id"
case ownerType = "owner-type"
case firstName = "first-name"
case lastName = "last-name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let id = try container.decode(UUID.self, forKey: .id)
let type = try container.decode(PostType.self, forKey: .type)
switch type {
case .post:
let title = try container.decode(String.self, forKey: .title)
let ownerId = try container.decode(UUID.self, forKey: .ownerId)
let ownerType = try container.decode(PostOwner.self, forKey: .ownerType)
self = .post(id: id, title: title, ownerId: ownerId, ownerType: ownerType)
case .member:
let firstName = try container.decode(String.self, forKey: .firstName)
let lastName = try container.decode(String.self, forKey: .lastName)
self = .member(id: id, firstName: firstName, lastName: lastName)
case .imageMedium:
let assetURL = try container.decode(URL.self, forKey: .assetUrl)
let ownerId = try container.decode(UUID.self, forKey: .ownerId)
let ownerType = try container.decode(ImageOwner.self, forKey: .ownerType)
self = .imageMedium(id: id, assetURL: assetURL, ownerId: ownerId, ownerType: ownerType)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .post(let id, let title, let ownerId, let ownerType):
try container.encode(PostType.post, forKey: .type)
try container.encode(id, forKey: .id)
try container.encode(title, forKey: .title)
try container.encode(ownerId, forKey: .ownerId)
try container.encode(ownerType, forKey: .ownerType)
case .member(let id, let firstName, let lastName):
try container.encode(PostType.member, forKey: .type)
try container.encode(id, forKey: .id)
try container.encode(firstName, forKey: .firstName)
try container.encode(lastName, forKey: .lastName)
case .imageMedium(let id, let assetURL, let ownerId, let ownerType):
try container.encode(PostType.imageMedium, forKey: .type)
try container.encode(id, forKey: .id)
try container.encode(assetURL, forKey: .assetUrl)
try container.encode(ownerId, forKey: .ownerId)
try container.encode(ownerType, forKey: .ownerType)
}
}
}
let jsonDecoder = JSONDecoder()
let result = try jsonDecoder.decode([String: [Post]].self, from: yourJSONData)
print(result)
对于当前帖子类型中未使用的字段,它有零个选项,并且UUID
s 被键入为UUID
,并且URL
s as在任何地方都不是 s 。URL
String
ownerType
被键入 asPostOwner
和ImageOwner
for.post
以及.imageMedium
为了额外的类型安全。
编辑:好的,我检查了问题的编辑:在您的 json 中,只有“.post”进入“数据”,其余进入“包含”。在我的答案中Post
, s 和Included
s 合并为一种类型。
所以它应该是这样的:
struct Post: Codable {
let id: UUID
let title: String
let ownerId: UUID
let ownerType: PostOwner
enum PostOwner: String, Codable {
case member
}
enum CodingKeys: String, CodingKey {
case id
case title
case ownerId = "owner-id"
case ownerType = "owner-type"
}
}
enum Included: Codable {
case member(id: UUID, firstName: String, lastName: String)
case imageMedium(id: UUID, assetURL: URL, ownerId: UUID, ownerType: ImageOwner)
enum PostType: String, Codable {
case member
case imageMedium = "image-medium"
}
enum ImageOwner: String, Codable {
case post
}
enum CodingKeys: String, CodingKey {
case id
case type
case title
case assetUrl = "asset-url"
case ownerId = "owner-id"
case ownerType = "owner-type"
case firstName = "first-name"
case lastName = "last-name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let id = try container.decode(UUID.self, forKey: .id)
let type = try container.decode(PostType.self, forKey: .type)
switch type {
case .member:
let firstName = try container.decode(String.self, forKey: .firstName)
let lastName = try container.decode(String.self, forKey: .lastName)
self = .member(id: id, firstName: firstName, lastName: lastName)
case .imageMedium:
let assetURL = try container.decode(URL.self, forKey: .assetUrl)
let ownerId = try container.decode(UUID.self, forKey: .ownerId)
let ownerType = try container.decode(ImageOwner.self, forKey: .ownerType)
self = .imageMedium(id: id, assetURL: assetURL, ownerId: ownerId, ownerType: ownerType)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .member(let id, let firstName, let lastName):
try container.encode(PostType.member, forKey: .type)
try container.encode(id, forKey: .id)
try container.encode(firstName, forKey: .firstName)
try container.encode(lastName, forKey: .lastName)
case .imageMedium(let id, let assetURL, let ownerId, let ownerType):
try container.encode(PostType.imageMedium, forKey: .type)
try container.encode(id, forKey: .id)
try container.encode(assetURL, forKey: .assetUrl)
try container.encode(ownerId, forKey: .ownerId)
try container.encode(ownerType, forKey: .ownerType)
}
}
}
Post
类型解析/验证可以/应该通过手动编码添加init(from: )
。