gpt4 book ai didi

ios - 如何从 Swift 4 中的解码器容器获取非解码属性?

转载 作者:可可西里 更新时间:2023-11-01 00:00:01 25 4
gpt4 key购买 nike

我正在使用 Decodable 协议(protocol)来解析从外部源接收到的 JSON。在解码我所知道的属性后,JSON 中可能仍有一些属性是未知的并且尚未被解码。例如,如果外部源在未来的某个时间点向 JSON 添加了一个新属性,我想通过将它们存储在 [String: Any] 字典(或一个替代方案),因此这些值不会被忽略。

问题是,在解码我所知道的属性后,容器上没有任何访问器来检索尚未解码的属性。我知道 decoder.unkeyedContainer() 我可以用它来迭代每个值,但这在我的情况下不起作用,因为为了让它起作用,你需要知道你的值类型正在迭代,但 JSON 中的值类型并不总是相同。

这是我正在努力实现的 Playground 上的一个例子:

// Playground
import Foundation

let jsonData = """
{
"name": "Foo",
"age": 21
}
""".data(using: .utf8)!

struct Person: Decodable {
enum CodingKeys: CodingKey {
case name
}

let name: String
let unknownAttributes: [String: Any]

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)

// I would like to store the `age` attribute in this dictionary
// but it would not be known at the time this code was written.
self.unknownAttributes = [:]
}
}

let decoder = JSONDecoder()
let person = try! decoder.decode(Person.self, from: jsonData)

// The `person.unknownAttributes` dictionary should
// contain the "age" attribute with a value of 21.

我希望 unknownAttributes 字典在这种情况下存储 age 属性和值,以及任何其他可能的值类型,如果它们从外部源添加到 JSON future 。

我想做这样的事情的原因是我可以保留 JSON 中存在的未知属性,以便在以后的代码更新中,一旦属性键已知,我就能够适本地处理它们。

我在 StackOverflow 和 Google 上进行了大量搜索,但还没有遇到过这种独特的情况。提前致谢!

最佳答案

你们不断想出新颖的方法来强调 Swift 4 编码 API...;)

支持所有 值类型的通用解决方案可能无法实现。但是,对于原始类型,您可以尝试这样做:

使用基于字符串的键创建一个简单的 CodingKey 类型:

struct UnknownCodingKey: CodingKey {
init?(stringValue: String) { self.stringValue = stringValue }
let stringValue: String

init?(intValue: Int) { return nil }
var intValue: Int? { return nil }
}

然后使用上面的UnknownCodingKey键控的标准KeyedDecodingContainer编写一个通用的解码函数:

func decodeUnknownKeys(from decoder: Decoder, with knownKeys: Set<String>) throws -> [String: Any] {
let container = try decoder.container(keyedBy: UnknownCodingKey.self)
var unknownKeyValues = [String: Any]()

for key in container.allKeys {
guard !knownKeys.contains(key.stringValue) else { continue }

func decodeUnknownValue<T: Decodable>(_ type: T.Type) -> Bool {
guard let value = try? container.decode(type, forKey: key) else {
return false
}
unknownKeyValues[key.stringValue] = value
return true
}
if decodeUnknownValue(String.self) { continue }
if decodeUnknownValue(Int.self) { continue }
if decodeUnknownValue(Double.self) { continue }
// ...
}
return unknownKeyValues
}

最后,使用decodeUnknownKeys函数来填充你的unknownAttributes字典:

struct Person: Decodable {
enum CodingKeys: CodingKey {
case name
}

let name: String
let unknownAttributes: [String: Any]

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)

let knownKeys = Set(container.allKeys.map { $0.stringValue })
self.unknownAttributes = try decodeUnknownKeys(from: decoder, with: knownKeys)
}
}

一个简单的测试:

let jsonData = """
{
"name": "Foo",
"age": 21,
"token": "ABC",
"rate": 1.234
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let person = try! decoder.decode(Person.self, from: jsonData)
print(person.name)
print(person.unknownAttributes)

打印:

Foo
["age": 21, "token": "ABC", "rate": 1.234]

关于ios - 如何从 Swift 4 中的解码器容器获取非解码属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47685801/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com