1. ホーム
  2. json

[解決済み] SwiftのDecodableプロトコルでネストしたJSON構造体をデコードする方法とは?

2022-09-23 21:14:23

質問

以下は私のJSONです。

{
    "id": 1,
    "user": {
        "user_name": "Tester",
        "real_info": {
            "full_name":"Jon Doe"
        }
    },
    "reviews_count": [
        {
            "count": 4
        }
    ]
}

以下は、保存してほしい構造です(不完全ですが)。

struct ServerResponse: Decodable {
    var id: String
    var username: String
    var fullName: String
    var reviewCount: Int

    enum CodingKeys: String, CodingKey {
       case id, 
       // How do i get nested values?
    }
}

私が見たのは アップルのドキュメント を見ましたが、JSONの異なるレベルを適切に行う方法がまだ理解できません。どんな助けでも大いに感謝します。

どのように解決するのですか?

もうひとつの方法は、JSON に密接に一致する中間モデルを作成することです (次のようなツールの助けを借りて)。 quicktype.io のようなツールの助けを借りて)、Swift にそれをデコードするメソッドを生成させ、最終的なデータモデルに必要なピースを選び出すことです。

// snake_case to match the JSON and hence no need to write CodingKey enums / struct
fileprivate struct RawServerResponse: Decodable {
    struct User: Decodable {
        var user_name: String
        var real_info: UserRealInfo
    }

    struct UserRealInfo: Decodable {
        var full_name: String
    }

    struct Review: Decodable {
        var count: Int
    }

    var id: Int
    var user: User
    var reviews_count: [Review]
}

struct ServerResponse: Decodable {
    var id: String
    var username: String
    var fullName: String
    var reviewCount: Int

    init(from decoder: Decoder) throws {
        let rawResponse = try RawServerResponse(from: decoder)

        // Now you can pick items that are important to your data model,
        // conveniently decoded into a Swift structure
        id = String(rawResponse.id)
        username = rawResponse.user.user_name
        fullName = rawResponse.user.real_info.full_name
        reviewCount = rawResponse.reviews_count.first!.count
    }
}

これはまた、簡単に反復して reviews_count を簡単に繰り返すことができます。