【发布时间】:2018-10-27 14:24:21
【问题描述】:
我有以下代码来提取包含在编码键中的 JSON:
let value = try! decoder.decode([String:Applmusic].self, from: $0["applmusic"])
这成功处理了以下 JSON:
{
"applmusic":{
"code":"AAPL",
"quality":"good",
"line":"She told me don't worry",
}
但是,无法从以下代码中提取编码密钥为applmusic 的 JSON:
{
"applmusic":{
"code":"AAPL",
"quality":"good",
"line":"She told me don't worry",
},
"spotify":{
"differentcode":"SPOT",
"music_quality":"good",
"spotify_specific_code":"absent in apple"
},
"amazon":{
"amzncode":"SPOT",
"music_quality":"good",
"stanley":"absent in apple"
}
}
applmusic、spotify 和 amazon 的数据模型不同。但是,我只需要提取applmusic 并省略其他编码键。
我的Swift 数据模型如下:
public struct Applmusic: Codable {
public let code: String
public let quality: String
public let line: String
}
API 以完整的 JSON 响应,我不能要求它只给我所需的字段。
如何只解码 json 的特定部分?看来,Decodable 需要我先反序列化整个 json,所以我必须知道它的完整数据模型。
显然,其中一种解决方案是创建一个单独的 Response 模型以包含 applmusic 参数,但它看起来像一个 hack:
public struct Response: Codable {
public struct Applmusic: Codable {
public let code: String
public let quality: String
public let line: String
}
// The only parameter is `applmusic`, ignoring the other parts - works fine
public let applmusic: Applmusic
}
您能否提出一种更好的方法来处理这种 JSON 结构?
更多见解
我在通用扩展中使用以下技术自动为我解码 API 响应。因此,我更愿意概括一种处理此类情况的方法,而无需创建Root 结构。如果我需要的密钥是 JSON 结构中的 3 层深度怎么办?
这是为我进行解码的扩展:
extension Endpoint where Response: Swift.Decodable {
convenience init(method: Method = .get,
path: Path,
codingKey: String? = nil,
parameters: Parameters? = nil) {
self.init(method: method, path: path, parameters: parameters, codingKey: codingKey) {
if let key = codingKey {
guard let value = try decoder.decode([String:Response].self, from: $0)[key] else {
throw RestClientError.valueNotFound(codingKey: key)
}
return value
}
return try decoder.decode(Response.self, from: $0)
}
}
}
API 是这样定义的:
extension API {
static func getMusic() -> Endpoint<[Applmusic]> {
return Endpoint(method: .get,
path: "/api/music",
codingKey: "applmusic")
}
}
【问题讨论】:
-
其中一种解决方案是只提取一个密钥的正确方法。
-
你的
Response仍然是正确的方法尝试在单独的对象中获取applmusic并尝试解码它可能会起作用 -
您可以在
init(decoder)期间通过nestedContainer完成此操作,而无需创建Response包装器 -
@vadian 您能否详细说明“仅提取一个密钥的正确方法”?谢谢。
-
@Tj3n 你能在这里发布一个简短的例子吗?
标签: ios json swift codable decodable