Swift Decodable Optional Key
Solution 1
You can use the following KeyedDecodingContainer
function:
func contains(_ key: KeyedDecodingContainer.Key) -> Bool
Returns a
Bool
value indicating whether the decoder contains a value associated with the given key. 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:
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
}
}
}
Solution 2
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)
you don't need to check if the container exist using contains(
.
Solution 3
Can you try pasting your sample JSON into quicktype to see what types it infers? 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.
Charlie Fish
Software Engineer (iOS @ ForeFlight) 🖥📱, student pilot ✈️, HUGE Colorado Avalanche fan 🥅, entrepreneur (rrainn, Inc.) ⭐️ Contact me ✉️, About me 👨🏻💻, Terms 📝, Website 🌐
Updated on June 11, 2022Comments
-
Charlie Fish about 2 years
(This is a follow-up from this question: Using Decodable protocol with multiples keys.)
I have the following Swift code:
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.For example the following JSON works to parse it using the code above.
{ "firstname": "Test", "lastname": "User", "age": {"realage": 29} }
And the following JSON works as well.
{ "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? Is there something similar to
decodeIfPresent
fornestedContainer
?