如何从通过 Moya.Response 查询返回的对象解析嵌套的 JSON 数组
How to parse nested JSON arrays from object returned via Moya.Response query
我正在尝试解析我的网络会话(通过 MoyaProvider 完成)产生的 JSON 对象。 returned JSON 对象中嵌套了 JSON 数组。它看起来像这样:
Edit: Link to the json file is here. results.json
{
“resultCount” : 50,
“results” :
[
{
“data1”: 1
“data2”: 2
},
{
“data1”: 1
“data2”: 2
},
{
“data1”: 1
“data2”: 2
}
]
}
现在使用 Moya,我可以像这样使用 Moya.Response API 获取数据:
let jsonObj = try response.mapJSON()
但我不想那样做,我想将它映射到我的模型结构。我在下面做了类似的事情。我已经检查过(通过 OPTION + MouseHover)objMovie 的类型是 [Movie]
let objMovie = try response.map(ITunesSearchResults<Movie>.self).results
我已经使用类似的技术遵循在线教程,但我
不明白为什么 objMovie 不包含执行上述行后的 return 值。我试着做了
print(obj.< propertyofMovie >)
但控制台上没有显示任何内容。
那给的是什么?
这里有一些代码片段。
iTunesSearchResults 在哪里:
struct ITunesSearchResults<T: Decodable>: Decodable {
let results: [T]
}
我的电影结构是这样的。它符合 JSON 嵌套数组属性中的键值。
struct Movie: Codable
{
let trackId: Int
let trackName: String
let trackGenre: String
let trackPrice: Int?
let longDescription: String
init(trackId: Int, trackName: String, trackGenre: String,
trackPrice:
Int?, /*trackImage: Thumbnail,*/ longDescription: String)
{
self.trackId = trackId
self.trackName = trackName
self.trackGenre = trackGenre
self.trackPrice = trackPrice ?? 0
self.longDescription = longDescription
//self.trackImage = trackImage //TODO: thumbnail: mapp url from json
}
private enum MovieCodingKeys: String, CodingKey
{
case trackId
case trackName
case trackGenre = "primaryGenreName"
case trackPrice
//case trackImage
case longDescription
}
init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: MovieCodingKeys.self)
trackId = try container.decode(Int.self, forKey: .trackId)
trackName = try container.decode(String.self, forKey: .trackName)
trackGenre = try container.decode(String.self, forKey: .trackGenre)
trackPrice = try container.decode(Int?.self, forKey: .trackPrice)
longDescription = try container.decode(String.self, forKey: .longDescription)
}
}
首先使用 Moya
的 Data
响应,因为您 do 想要用 Decodable
解码 JSON例如
let data = response.data
您的 Movie
结构太复杂,显式 CodingKeys
并且根本不需要 init
方法,您可以免费获得它们。这足够了:
struct ITunesSearchResults<T: Decodable>: Decodable {
let results: [T]
}
struct Movie: Decodable
{
let trackId: Int
let trackName: String
let trackGenre: String?
let trackPrice: Double?
let longDescription: String
}
请注意 trackPrice
是 Double
并且 trackGenre
和 trackPrice
是可选的。
现在简单解码
do {
let result = try JSONDecoder().decode(ITunesSearchResults<Movie>.self, from: data)
print(result)
} catch { print(error) }
注:
从不 使用类似
的语法
try container.decode(Int?.self, forKey: .trackPrice)
有decodeIfPresent
try container.decodeIfPresent(Int.self, forKey: .trackPrice)
最大的好处是如果密钥存在但类型错误,就像在这个具体案例中一样,它会抛出错误。
我正在尝试解析我的网络会话(通过 MoyaProvider 完成)产生的 JSON 对象。 returned JSON 对象中嵌套了 JSON 数组。它看起来像这样:
Edit: Link to the json file is here. results.json
{
“resultCount” : 50,
“results” :
[
{
“data1”: 1
“data2”: 2
},
{
“data1”: 1
“data2”: 2
},
{
“data1”: 1
“data2”: 2
}
]
}
现在使用 Moya,我可以像这样使用 Moya.Response API 获取数据:
let jsonObj = try response.mapJSON()
但我不想那样做,我想将它映射到我的模型结构。我在下面做了类似的事情。我已经检查过(通过 OPTION + MouseHover)objMovie 的类型是 [Movie]
let objMovie = try response.map(ITunesSearchResults<Movie>.self).results
我已经使用类似的技术遵循在线教程,但我 不明白为什么 objMovie 不包含执行上述行后的 return 值。我试着做了
print(obj.< propertyofMovie >)
但控制台上没有显示任何内容。
那给的是什么?
这里有一些代码片段。 iTunesSearchResults 在哪里:
struct ITunesSearchResults<T: Decodable>: Decodable {
let results: [T]
}
我的电影结构是这样的。它符合 JSON 嵌套数组属性中的键值。
struct Movie: Codable
{
let trackId: Int
let trackName: String
let trackGenre: String
let trackPrice: Int?
let longDescription: String
init(trackId: Int, trackName: String, trackGenre: String,
trackPrice:
Int?, /*trackImage: Thumbnail,*/ longDescription: String)
{
self.trackId = trackId
self.trackName = trackName
self.trackGenre = trackGenre
self.trackPrice = trackPrice ?? 0
self.longDescription = longDescription
//self.trackImage = trackImage //TODO: thumbnail: mapp url from json
}
private enum MovieCodingKeys: String, CodingKey
{
case trackId
case trackName
case trackGenre = "primaryGenreName"
case trackPrice
//case trackImage
case longDescription
}
init(from decoder: Decoder) throws
{
let container = try decoder.container(keyedBy: MovieCodingKeys.self)
trackId = try container.decode(Int.self, forKey: .trackId)
trackName = try container.decode(String.self, forKey: .trackName)
trackGenre = try container.decode(String.self, forKey: .trackGenre)
trackPrice = try container.decode(Int?.self, forKey: .trackPrice)
longDescription = try container.decode(String.self, forKey: .longDescription)
}
}
首先使用 Moya
的 Data
响应,因为您 do 想要用 Decodable
解码 JSON例如
let data = response.data
您的 Movie
结构太复杂,显式 CodingKeys
并且根本不需要 init
方法,您可以免费获得它们。这足够了:
struct ITunesSearchResults<T: Decodable>: Decodable {
let results: [T]
}
struct Movie: Decodable
{
let trackId: Int
let trackName: String
let trackGenre: String?
let trackPrice: Double?
let longDescription: String
}
请注意 trackPrice
是 Double
并且 trackGenre
和 trackPrice
是可选的。
现在简单解码
do {
let result = try JSONDecoder().decode(ITunesSearchResults<Movie>.self, from: data)
print(result)
} catch { print(error) }
注:
从不 使用类似
的语法try container.decode(Int?.self, forKey: .trackPrice)
有decodeIfPresent
try container.decodeIfPresent(Int.self, forKey: .trackPrice)
最大的好处是如果密钥存在但类型错误,就像在这个具体案例中一样,它会抛出错误。