(これは、この質問からのフォローアップです: 複数のキーでDecodableプロトコルを使用 。)
私は次のSwiftコードを持っています:
let additionalInfo = try values.nestedContainer(keyedBy: UserInfoKeys.self, forKey: .age)
age = try additionalInfo.decodeIfPresent(Int.self, forKey: .realage)
decodeIfPresent
を使用し、プロパティを持っていない場合でも、オプションの変数であればそれを正しく処理します。
たとえば、次のJSONは上記のコードを使用して解析します。
{
"firstname": "Test",
"lastname": "User",
"age": {"realage": 29}
}
また、次のJSONも機能します。
{
"firstname": "Test",
"lastname": "User",
"age": {"notrealage": 30}
}
しかし、以下は機能しません。
{
"firstname": "Test",
"lastname": "User"
}
3つの例すべてを機能させるにはどうすればよいですか? decodeIfPresent
にnestedContainer
に似たものはありますか?
次の KeyedDecodingContainer
関数を使用できます。
func contains(_ key: KeyedDecodingContainer.Key) -> Bool
指定されたキーに関連付けられた値がデコーダに含まれているかどうかを示す
Bool
値を返します。指定されたキーに関連付けられた値は、データ形式に応じてヌル値になる場合があります。
たとえば、"age"
キーが存在するbefore対応するネストされたコンテナを要求する:
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
}
}
}
私はこの問題を抱えていて、他の誰かに役立つ場合に備えて、この解決策を見つけました:
let ageContainer = try? values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
self.age = try ageContainer?.decodeIfPresent(Int.self, forKey: .realAge)
キーはtry?values.nestedContainer...
オプションのコンテナがある場合。これは、contains
がキーであるかどうかを確認する必要がないということです。
サンプルJSONを quicktype に貼り付けて、推測される型を確認してみてください。あなたの質問に基づいて、私はあなたのサンプルを貼り付けて、以下を得ました:
struct UserInfo: Codable {
let firstname: String
let age: Age?
let lastname: String
}
struct Age: Codable {
let realage: Int?
}
作成UserInfo.age
およびAge.realage
オプションが機能するのは、それがあなたが達成しようとしているものである場合です。