web-dev-qa-db-ja.com

Swift Decodable Optional Key

(これは、この質問からのフォローアップです: 複数のキーで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つの例すべてを機能させるにはどうすればよいですか? decodeIfPresentnestedContainerに似たものはありますか?

13
Charlie Fish

次の 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
        }
    }
}
42
Paulo Mattos

私はこの問題を抱えていて、他の誰かに役立つ場合に備えて、この解決策を見つけました:

let ageContainer = try? values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
self.age = try ageContainer?.decodeIfPresent(Int.self, forKey: .realAge)

キーはtry?values.nestedContainer...オプションのコンテナがある場合。これは、containsがキーであるかどうかを確認する必要がないということです。

1
TomCobo

サンプルJSONを quicktype に貼り付けて、推測される型を確認してみてください。あなたの質問に基づいて、私はあなたのサンプルを貼り付けて、以下を得ました:

struct UserInfo: Codable {
    let firstname: String
    let age: Age?
    let lastname: String
}

struct Age: Codable {
    let realage: Int?
}

作成UserInfo.ageおよびAge.realageオプションが機能するのは、それがあなたが達成しようとしているものである場合です。

1
David Siegel