可编码:展平结构
Encodable: Flattening structures
假设我有一些具有 JSON 表示的类型:
{
"count": 3,
"name": "Pianos",
"type": "instrument",
"id": 1,
}
假设我想将其表示为一个 Swift 对象,如下所示:
struct SomeObject: Codable { // this is the object I'd like to represent
let id: Int
let details: SomeDetails
}
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
解码此对象是轻而易举的事。但是在这种情况下编码如何工作,以便我可以编码成一个平面结构——我用来创建这个对象并在上面的 JSON 示例中共享的相同结构?
But how would encoding work in this instance?
有效:
struct SomeObject: Codable {
let id: Int
let details: SomeDetails
}
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
let someobject = SomeObject(id: 10, details: SomeDetails(count: 3, name: "ho", type: "hey"))
let json = try! JSONEncoder().encode(someobject)
如果硬要人为压扁,干脆自己写encode(to:)
,像这样:
struct SomeObject: Codable {
let id: Int
let details: SomeDetails
enum Keys : String, CodingKey {
case id
case count
case name
case type
}
func encode(to enc: Encoder) throws {
var con = try enc.container(keyedBy: Keys.self)
try con.encode(id, forKey: .id)
try con.encode(details.count, forKey: .count)
try con.encode(details.name, forKey: .name)
try con.encode(details.type, forKey: .type)
}
}
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
let someobject = SomeObject(id: 10, details: SomeDetails(count: 3, name: "ho", type: "hey"))
let json = try! JSONEncoder().encode(someobject)
如果以后有人读到这篇文章(嗨!),只需进入包含抽象值的构造类型即可。
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
struct SomeObject: Codable {
let id: Int
let details: SomeDetails
enum CodingKeys: String, CodingKey {
case id
}
enum DetailKeys: String, CodingKey {
case count, name, type
}
init(from decoder: Decoder) throws {
let topLevelContainer = try decoder.container(keyedBy: CodingKeys.self)
let detailContainer = try decoder.container(keyedBy: DetailKeys.self)
id = try topLevelContainer.decode(Int.self, forKey: .id)
details = SomeDetails(
count: try detailContainer.decode(Int.self, forKey: .count),
name: try detailContainer.decode(String.self, forKey: .name),
type: try detailContainer.decode(String.self, forKey: .type))
}
func encode(to encoder: Encoder) throws {
var topLevelContainer = encoder.container(keyedBy: CodingKeys.self)
try topLevelContainer.encode(id, forKey: .id)
var detailContainer = encoder.container(keyedBy: DetailKeys.self)
try detailContainer.encode(details.count, forKey: .count)
try detailContainer.encode(details.name, forKey: .name)
try detailContainer.encode(details.type, forKey: .type)
}
}
对之前答案的改进。无需手动编码或解码您可以转发初始化程序的其他对象。
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
struct SomeObject: Codable {
enum CodingKeys: String, CodingKey {
case id
}
let id: Int
let details: SomeDetails
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
details = try SomeDetails(from: decoder)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try details.encode(to: encoder)
}
}
对于一些额外的糖分,您可以使用 Swift 5 秒动态成员查找,以便您可以很好地访问这些成员 object.name
。
@dynamicMemberLookup
struct SomeObject {
...
subscript<T>(dynamicMember member: KeyPath<SomeDetails, T>) -> T {
details[keyPath: member]
}
}
假设我有一些具有 JSON 表示的类型:
{
"count": 3,
"name": "Pianos",
"type": "instrument",
"id": 1,
}
假设我想将其表示为一个 Swift 对象,如下所示:
struct SomeObject: Codable { // this is the object I'd like to represent
let id: Int
let details: SomeDetails
}
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
解码此对象是轻而易举的事。但是在这种情况下编码如何工作,以便我可以编码成一个平面结构——我用来创建这个对象并在上面的 JSON 示例中共享的相同结构?
But how would encoding work in this instance?
有效:
struct SomeObject: Codable {
let id: Int
let details: SomeDetails
}
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
let someobject = SomeObject(id: 10, details: SomeDetails(count: 3, name: "ho", type: "hey"))
let json = try! JSONEncoder().encode(someobject)
如果硬要人为压扁,干脆自己写encode(to:)
,像这样:
struct SomeObject: Codable {
let id: Int
let details: SomeDetails
enum Keys : String, CodingKey {
case id
case count
case name
case type
}
func encode(to enc: Encoder) throws {
var con = try enc.container(keyedBy: Keys.self)
try con.encode(id, forKey: .id)
try con.encode(details.count, forKey: .count)
try con.encode(details.name, forKey: .name)
try con.encode(details.type, forKey: .type)
}
}
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
let someobject = SomeObject(id: 10, details: SomeDetails(count: 3, name: "ho", type: "hey"))
let json = try! JSONEncoder().encode(someobject)
如果以后有人读到这篇文章(嗨!),只需进入包含抽象值的构造类型即可。
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
struct SomeObject: Codable {
let id: Int
let details: SomeDetails
enum CodingKeys: String, CodingKey {
case id
}
enum DetailKeys: String, CodingKey {
case count, name, type
}
init(from decoder: Decoder) throws {
let topLevelContainer = try decoder.container(keyedBy: CodingKeys.self)
let detailContainer = try decoder.container(keyedBy: DetailKeys.self)
id = try topLevelContainer.decode(Int.self, forKey: .id)
details = SomeDetails(
count: try detailContainer.decode(Int.self, forKey: .count),
name: try detailContainer.decode(String.self, forKey: .name),
type: try detailContainer.decode(String.self, forKey: .type))
}
func encode(to encoder: Encoder) throws {
var topLevelContainer = encoder.container(keyedBy: CodingKeys.self)
try topLevelContainer.encode(id, forKey: .id)
var detailContainer = encoder.container(keyedBy: DetailKeys.self)
try detailContainer.encode(details.count, forKey: .count)
try detailContainer.encode(details.name, forKey: .name)
try detailContainer.encode(details.type, forKey: .type)
}
}
对之前答案的改进。无需手动编码或解码您可以转发初始化程序的其他对象。
struct SomeDetails: Codable {
let count: Int
let name: String
let type: String
}
struct SomeObject: Codable {
enum CodingKeys: String, CodingKey {
case id
}
let id: Int
let details: SomeDetails
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
details = try SomeDetails(from: decoder)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try details.encode(to: encoder)
}
}
对于一些额外的糖分,您可以使用 Swift 5 秒动态成员查找,以便您可以很好地访问这些成员 object.name
。
@dynamicMemberLookup
struct SomeObject {
...
subscript<T>(dynamicMember member: KeyPath<SomeDetails, T>) -> T {
details[keyPath: member]
}
}