使用 decodable 在单行中捕获嵌套对象数组
using decodable to capture array of nested objects in single line
下面是我的 json 响应和我需要从中构建的结构。
条件:我不想创建除 Response,Media 之外的任何其他结构,并且希望按照下面指定的方式在单行中进行解析。
{
"name": "xxxx",
"title": "xxxxxxx",
"assets": [
{
"items": [
{
"id": "eeee",
"desc": "rrrrrr"
}, {
"id": "eeee",
}, {
"desc": "rrrrrr"
}]
}]
}
struct Response {
let name : String
let title : string
let items : [Media]
private enum codingKeys : String, CodingKey {
case name = "name"
case title = "title"
case items = "assets.items"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: codingKeys.self)
name = try container.decode(String.self, forKey: .name)
title = try container.decode(TrayLayout.self, forKey: .title)
items = try container.decode([Media].self, forKey: .items)
}
}
你可以试试这个:
struct Response: Decodable {
let name, title: String
let assets: [Assets]
}
struct Assets: Decodable {
let items: [Items]
}
struct Items: Decodable {
let id, desc: String
}
然后你就可以这样解码了:
guard let response = try? JSONDecoder().decode(Response.self, from: data) else { print("Response not parsed"); return }
我设法找到了解决您问题的方法。
考虑以下是示例 json
let jsonString = """
{
"name": "xxxx",
"title": "xxxxxxx",
"assets": [
{
"items": [
{
"id": "id11",
"desc": "desc11"
}, {
"id": "id12",
}, {
"desc": "desc13"
}]
},{
"items": [
{
"id": "id21",
"desc": "desc21"
}, {
"id": "id22",
}, {
"desc": "desc23"
}]
}]
}
"""
您的结构如下所示
struct Media: Codable {
let id,desc: String?
enum CodingKeys: String, CodingKey {
case id,desc
}
}
struct Response: Decodable {
let name,title: String?
let items: [Media]?
enum CodingKeys: String, CodingKey {
case name,title,items
case assets = "assets"
}
// Decoding
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
title = try container.decode(String.self, forKey: .title)
// Here as the assets contains array of object which has a key as items and then again consist of a array of Media we need to decode as below
let assets = try container.decode([[String:[Media]]].self, forKey: .assets)
// At this stage will get assets with a array of array so we first map and retrive the items and then reduce them to one single array
items = assets.compactMap{[=11=][CodingKeys.items.rawValue]}.reduce([], +)
}
}
最后是时候如下使用了
let data = jsonString.data(using: .utf8)!
let myResponse = try! JSONDecoder().decode(Response.self, from: data)
现在您可以访问如下数据
myResponse.name
myResponse.title
myResponse.items
希望这个基本代码能帮助您实现您想要做的事情。然后你可以继续做更多的嵌套解析。
感谢 Nic Laughter
such a detailed article;通过参考我设法提供了上述解决方案。
找到新方法:
struct Media: Codable {
let id,desc: String?
enum CodingKeys: String, CodingKey {
case id,desc
}
}
struct Response: Decodable, CustomStringConvertible {
let name,title: String?
@NestedKey
let items: [Media]?
enum CodingKeys: String,NestableCodingKey {
case name,title,
case items = "assets/items"
}
}
下面是我的 json 响应和我需要从中构建的结构。
条件:我不想创建除 Response,Media 之外的任何其他结构,并且希望按照下面指定的方式在单行中进行解析。
{
"name": "xxxx",
"title": "xxxxxxx",
"assets": [
{
"items": [
{
"id": "eeee",
"desc": "rrrrrr"
}, {
"id": "eeee",
}, {
"desc": "rrrrrr"
}]
}]
}
struct Response {
let name : String
let title : string
let items : [Media]
private enum codingKeys : String, CodingKey {
case name = "name"
case title = "title"
case items = "assets.items"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: codingKeys.self)
name = try container.decode(String.self, forKey: .name)
title = try container.decode(TrayLayout.self, forKey: .title)
items = try container.decode([Media].self, forKey: .items)
}
}
你可以试试这个:
struct Response: Decodable {
let name, title: String
let assets: [Assets]
}
struct Assets: Decodable {
let items: [Items]
}
struct Items: Decodable {
let id, desc: String
}
然后你就可以这样解码了:
guard let response = try? JSONDecoder().decode(Response.self, from: data) else { print("Response not parsed"); return }
我设法找到了解决您问题的方法。
考虑以下是示例 json
let jsonString = """
{
"name": "xxxx",
"title": "xxxxxxx",
"assets": [
{
"items": [
{
"id": "id11",
"desc": "desc11"
}, {
"id": "id12",
}, {
"desc": "desc13"
}]
},{
"items": [
{
"id": "id21",
"desc": "desc21"
}, {
"id": "id22",
}, {
"desc": "desc23"
}]
}]
}
"""
您的结构如下所示
struct Media: Codable {
let id,desc: String?
enum CodingKeys: String, CodingKey {
case id,desc
}
}
struct Response: Decodable {
let name,title: String?
let items: [Media]?
enum CodingKeys: String, CodingKey {
case name,title,items
case assets = "assets"
}
// Decoding
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
title = try container.decode(String.self, forKey: .title)
// Here as the assets contains array of object which has a key as items and then again consist of a array of Media we need to decode as below
let assets = try container.decode([[String:[Media]]].self, forKey: .assets)
// At this stage will get assets with a array of array so we first map and retrive the items and then reduce them to one single array
items = assets.compactMap{[=11=][CodingKeys.items.rawValue]}.reduce([], +)
}
}
最后是时候如下使用了
let data = jsonString.data(using: .utf8)!
let myResponse = try! JSONDecoder().decode(Response.self, from: data)
现在您可以访问如下数据
myResponse.name
myResponse.title
myResponse.items
希望这个基本代码能帮助您实现您想要做的事情。然后你可以继续做更多的嵌套解析。
感谢 Nic Laughter
such a detailed article;通过参考我设法提供了上述解决方案。
找到新方法:
struct Media: Codable {
let id,desc: String?
enum CodingKeys: String, CodingKey {
case id,desc
}
}
struct Response: Decodable, CustomStringConvertible {
let name,title: String?
@NestedKey
let items: [Media]?
enum CodingKeys: String,NestableCodingKey {
case name,title,
case items = "assets/items"
}
}