Swift 4 可解码:来自嵌套数组的结构
Swift 4 Decodable: struct from nested array
鉴于以下 JSON 文档,我想创建一个具有四个属性的 struct
:filmCount
(Int)、year
(Int)、category
(字符串)和 actor
(Actor 数组)。
{
"filmCount": 5,
"year": 2018,
"category": "Other",
"actors":{
"nodes":[
{
"actor":{
"id":0,
"name":"Daniel Craig"
}
},
{
"actor":{
"id":1,
"name":"Naomie Harris"
}
},
{
"actor":{
"id":2,
"name":"Rowan Atkinson"
}
}
]
}
}
PlacerholderData
是一个存储三个主要属性和应从 actors
属性 中的嵌套 nodes
容器中检索的参与者列表的结构JSON 对象。
Placerholder 数据:
struct PlaceholderData: Codable {
let filmCount: Int
let year: Int
let category: String
let actors: [Actor]
}
Actor.swift:
struct Actor: Codable {
let id: Int
let name: String
}
我试图通过提供我自己的 init
来手动初始化解码器容器中的值来做到这一点。我怎样才能解决这个问题而不必有一个存储 nodes
对象的中间结构?
你可以使用 nestedContainer(keyedBy:) 和 nestedUnkeyedContainer(forKey:) 像这样解码嵌套数组和字典来转换它进入你想要的结构。你在 init(decoder: ) 中的解码可能看起来像这样,
用于解码的 Actor 扩展,
extension Actor: Decodable {
enum CodingKeys: CodingKey { case id, name }
enum ActorKey: CodingKey { case actor }
init(from decoder: Decoder) throws {
let rootKeys = try decoder.container(keyedBy: ActorKey.self)
let actorContainer = try rootKeys.nestedContainer(keyedBy: CodingKeys.self,
forKey: .actor)
try id = actorContainer.decode(Int.self,
forKey: .id)
try name = actorContainer.decode(String.self,
forKey: .name)
}
}
用于解码的占位符数据扩展,
extension PlaceholderData: Decodable {
enum CodingKeys: CodingKey { case filmCount, year, category, actors }
enum NodeKeys: CodingKey { case nodes }
init(from decoder: Decoder) throws {
let rootContainer = try decoder.container(keyedBy: CodingKeys.self)
try filmCount = rootContainer.decode(Int.self,
forKey: .filmCount)
try year = rootContainer.decode(Int.self,
forKey: .year)
try category = rootContainer.decode(String.self,
forKey: .category)
let actorsNode = try rootContainer.nestedContainer(keyedBy: NodeKeys.self,
forKey: .actors)
var nodes = try actorsNode.nestedUnkeyedContainer(forKey: .nodes)
var allActors: [Actor] = []
while !nodes.isAtEnd {
let actor = try nodes.decode(Actor.self)
allActors += [actor]
}
actors = allActors
}
}
然后,你可以这样解码,
let decoder = JSONDecoder()
do {
let placeholder = try decoder.decode(PlaceholderData.self, from: jsonData)
print(placeholder)
} catch {
print(error)
}
这里,基本思路是使用 nestedContainer(keyedBy:) 解码字典容器,使用 nestedUnkeyedContainer(forKey:) 解码数组容器
鉴于以下 JSON 文档,我想创建一个具有四个属性的 struct
:filmCount
(Int)、year
(Int)、category
(字符串)和 actor
(Actor 数组)。
{
"filmCount": 5,
"year": 2018,
"category": "Other",
"actors":{
"nodes":[
{
"actor":{
"id":0,
"name":"Daniel Craig"
}
},
{
"actor":{
"id":1,
"name":"Naomie Harris"
}
},
{
"actor":{
"id":2,
"name":"Rowan Atkinson"
}
}
]
}
}
PlacerholderData
是一个存储三个主要属性和应从 actors
属性 中的嵌套 nodes
容器中检索的参与者列表的结构JSON 对象。
Placerholder 数据:
struct PlaceholderData: Codable {
let filmCount: Int
let year: Int
let category: String
let actors: [Actor]
}
Actor.swift:
struct Actor: Codable {
let id: Int
let name: String
}
我试图通过提供我自己的 init
来手动初始化解码器容器中的值来做到这一点。我怎样才能解决这个问题而不必有一个存储 nodes
对象的中间结构?
你可以使用 nestedContainer(keyedBy:) 和 nestedUnkeyedContainer(forKey:) 像这样解码嵌套数组和字典来转换它进入你想要的结构。你在 init(decoder: ) 中的解码可能看起来像这样,
用于解码的 Actor 扩展,
extension Actor: Decodable {
enum CodingKeys: CodingKey { case id, name }
enum ActorKey: CodingKey { case actor }
init(from decoder: Decoder) throws {
let rootKeys = try decoder.container(keyedBy: ActorKey.self)
let actorContainer = try rootKeys.nestedContainer(keyedBy: CodingKeys.self,
forKey: .actor)
try id = actorContainer.decode(Int.self,
forKey: .id)
try name = actorContainer.decode(String.self,
forKey: .name)
}
}
用于解码的占位符数据扩展,
extension PlaceholderData: Decodable {
enum CodingKeys: CodingKey { case filmCount, year, category, actors }
enum NodeKeys: CodingKey { case nodes }
init(from decoder: Decoder) throws {
let rootContainer = try decoder.container(keyedBy: CodingKeys.self)
try filmCount = rootContainer.decode(Int.self,
forKey: .filmCount)
try year = rootContainer.decode(Int.self,
forKey: .year)
try category = rootContainer.decode(String.self,
forKey: .category)
let actorsNode = try rootContainer.nestedContainer(keyedBy: NodeKeys.self,
forKey: .actors)
var nodes = try actorsNode.nestedUnkeyedContainer(forKey: .nodes)
var allActors: [Actor] = []
while !nodes.isAtEnd {
let actor = try nodes.decode(Actor.self)
allActors += [actor]
}
actors = allActors
}
}
然后,你可以这样解码,
let decoder = JSONDecoder()
do {
let placeholder = try decoder.decode(PlaceholderData.self, from: jsonData)
print(placeholder)
} catch {
print(error)
}
这里,基本思路是使用 nestedContainer(keyedBy:) 解码字典容器,使用 nestedUnkeyedContainer(forKey:) 解码数组容器