Oli*_*ain 6 swift codable decodable
我正在尝试解码来自第三方 API 的 JSON 响应,其中包含已进行 base64 编码的嵌套/子 JSON。
人为的示例 JSON
{
"id": 1234,
"attributes": "eyAibmFtZSI6ICJzb21lLXZhbHVlIiB9",
}
Run Code Online (Sandbox Code Playgroud)
PS"eyAibmFtZSI6ICJzb21lLXZhbHVlIiB9"是 { 'name': 'some-value' }base64 编码的。
我目前有一些代码可以对此进行解码,但不幸JSONDecoder()的是init,为了这样做,我必须重新实例化一个额外的内部,这并不酷......
人为的示例代码
struct Attributes: Decodable {
let name: String
}
struct Model: Decodable {
let id: Int64
let attributes: Attributes
private enum CodingKeys: String, CodingKey {
case id
case attributes
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(Int64.self, forKey: .id)
let encodedAttributesString = try container.decode(String.self, forKey: .attributes)
guard let attributesData = Data(base64Encoded: encodedAttributesString) else {
fatalError()
}
// HERE IS WHERE I NEED HELP
self.attributes = try JSONDecoder().decode(Attributes.self, from: attributesData)
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法在不实例化额外的情况下实现解码JSONDecoder?
PS:我无法控制响应格式,也无法更改。
我发现这个问题很有趣,所以这里有一个可能的解决方案,即为主解码器提供一个额外的解决方案userInfo:
extension CodingUserInfoKey {
static let additionalDecoder = CodingUserInfoKey(rawValue: "AdditionalDecoder")!
}
var decoder = JSONDecoder()
let additionalDecoder = JSONDecoder() //here you can put the same one, you can add different options, same ones, etc.
decoder.userInfo = [CodingUserInfoKey.additionalDecoder: additionalDecoder]
Run Code Online (Sandbox Code Playgroud)
因为我们使用的主要方法JSONDecoder()是func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable并且我想保留它,所以我创建了一个协议:
protocol BasicDecoder {
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable
}
extension JSONDecoder: BasicDecoder {}
Run Code Online (Sandbox Code Playgroud)
我尊重JSONDecoder它(因为它已经尊重了......)
现在,为了玩一点并检查可以做什么,我创建了一个自定义解码器,就像您所说的 XML 解码器一样,它是基本的,并且只是为了好玩(即:不要在家里复制它^ ^):
struct CustomWithJSONSerialization: BasicDecoder {
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable {
guard let dict = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { fatalError() }
return Attributes(name: dict["name"] as! String) as! T
}
}
Run Code Online (Sandbox Code Playgroud)
所以,init(from:):
guard let attributesData = Data(base64Encoded: encodedAttributesString) else { fatalError() }
guard let additionalDecoder = decoder.userInfo[.additionalDecoder] as? BasicDecoder else { fatalError() }
self.attributes = try additionalDecoder.decode(Attributes.self, from: attributesData)
Run Code Online (Sandbox Code Playgroud)
现在我们就来尝试一下吧!
var decoder = JSONDecoder()
let additionalDecoder = JSONDecoder()
decoder.userInfo = [CodingUserInfoKey.additionalDecoder: additionalDecoder]
var decoder2 = JSONDecoder()
let additionalDecoder2 = CustomWithJSONSerialization()
decoder2.userInfo = [CodingUserInfoKey.additionalDecoder: additionalDecoder]
let jsonStr = """
{
"id": 1234,
"attributes": "eyAibmFtZSI6ICJzb21lLXZhbHVlIiB9",
}
"""
let jsonData = jsonStr.data(using: .utf8)!
do {
let value = try decoder.decode(Model.self, from: jsonData)
print("1: \(value)")
let value2 = try decoder2.decode(Model.self, from: jsonData)
print("2: \(value2)")
}
catch {
print("Error: \(error)")
}
Run Code Online (Sandbox Code Playgroud)
输出:
$> 1: Model(id: 1234, attributes: Quick.Attributes(name: "some-value"))
$> 2: Model(id: 1234, attributes: Quick.Attributes(name: "some-value"))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
300 次 |
| 最近记录: |