[英]Swift Decodable Optional Key
(This is a follow-up from this question: Using Decodable protocol with multiples keys .) (这是这个问题的后续: Using Decodable protocol with multiples keys 。)
I have the following Swift code:我有以下 Swift 代码:
let additionalInfo = try values.nestedContainer(keyedBy: UserInfoKeys.self, forKey: .age)
age = try additionalInfo.decodeIfPresent(Int.self, forKey: .realage)
I know that if I use decodeIfPresent
and don't have the property it will still handle it correctly if it's an optional variable.我知道如果我使用
decodeIfPresent
并且没有属性,如果它是一个可选变量,它仍然会正确处理它。
For example the following JSON works to parse it using the code above.例如,下面的 JSON 可以使用上面的代码解析它。
{
"firstname": "Test",
"lastname": "User",
"age": {"realage": 29}
}
And the following JSON works as well.以下 JSON 也适用。
{
"firstname": "Test",
"lastname": "User",
"age": {"notrealage": 30}
}
But the following doesn't work.但以下不起作用。
{
"firstname": "Test",
"lastname": "User"
}
How can I make all 3 examples work?我怎样才能让所有 3 个例子都有效? Is there something similar to
decodeIfPresent
for nestedContainer
?是否有类似于
decodeIfPresent
用于nestedContainer
?
You can use the following KeyedDecodingContainer
function:您可以使用以下
KeyedDecodingContainer
函数:
func contains(_ key: KeyedDecodingContainer.Key) -> Bool
Returns a
Bool
value indicating whether the decoder contains a value associated with the given key.返回一个
Bool
值,指示解码器是否包含与给定键关联的值。 The value associated with the given key may be a null value as appropriate for the data format.与给定键关联的值可以是适合数据格式的空值。
For instance, to check if the "age"
key exists before requesting the corresponding nested container:例如,在请求相应的嵌套容器之前检查
"age"
键是否存在:
struct Person: Decodable {
let firstName, lastName: String
let age: Int?
enum CodingKeys: String, CodingKey {
case firstName = "firstname"
case lastName = "lastname"
case age
}
enum AgeKeys: String, CodingKey {
case realAge = "realage"
case fakeAge = "fakeage"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.firstName = try values.decode(String.self, forKey: .firstName)
self.lastName = try values.decode(String.self, forKey: .lastName)
if values.contains(.age) {
let age = try values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
self.age = try age.decodeIfPresent(Int.self, forKey: .realAge)
} else {
self.age = nil
}
}
}
I had this issue and I found this solution, just in case is helpful to somebody else:我遇到了这个问题,我找到了这个解决方案,以防万一对其他人有帮助:
let ageContainer = try? values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
self.age = try ageContainer?.decodeIfPresent(Int.self, forKey: .realAge)
If you have an optional container, using try? values.nestedContainer(keyedBy:forKey)
如果你有一个可选的容器,使用
try? values.nestedContainer(keyedBy:forKey)
try? values.nestedContainer(keyedBy:forKey)
you don't need to check if the container exist using contains(
. try? values.nestedContainer(keyedBy:forKey)
你不需要使用contains(
来检查容器是否存在。
Can you try pasting your sample JSON into quicktype to see what types it infers?您可以尝试将示例 JSON 粘贴到quicktype 中以查看它推断出哪些类型吗? Based on your question, I pasted your samples and got:
根据您的问题,我粘贴了您的样本并得到:
struct UserInfo: Codable {
let firstname: String
let age: Age?
let lastname: String
}
struct Age: Codable {
let realage: Int?
}
Making UserInfo.age
and Age.realage
optionals works, if that's what you're trying to accomplish.使
UserInfo.age
和Age.realage
选项起作用,如果这是您要完成的工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.