文書   >   Swift 標準ライブラリ   >   Encoding,Decoding   >   カスタム型のコード化と復号化
記事
カスタム型のコード化と復号化
JSON などの外部表現との互換性のために、データ型をコード化可能かつ復号化可能にします。
概観
多くのプログラミングタスクでは、ネットワーク接続を介してデータを送信したり、データをディスクに保存したり、API やサービスにデータを送信したりします。これらのタスクでは、データが転送されている間に中間フォーマットとの間でデータのコード化および復号化が必要になることがよくあります。
Swift 標準ライブラリは、データのコード化と復号化に対する標準化されたアプローチを定義しています。カスタム型で Encodable および Decodable プロトコルを実装することで、このアプローチを採用して下さい。これらのプロトコルを採用することで、Encoder および Decoder プロトコルの実装でデータを取得し、JSON やプロパティリストなどの外部表現との間でコード化または復号化することができます。コード化と復号化の両方をサポートするには、Encodable と Decodable プロトコルを組み合わせた Codable への準拠を宣言します。このプロセスは、あなたの型を コード化可能 (codable) にすることとして知られています。
自動的にコード化と復号化
型をコード化可能にする最も簡単な方法は、既にコード化可能 (Codable) な型を使ってそのプロパティを宣言することです。これらの型には、String、Int、Double などの標準ライブラリ型があります。Date、Data、URL などの Foundation 型もあります。プロパティがコード化可能な、どの型もその準拠性を宣言するだけで自動的に Codable に準拠します。
ランドマーク(landmark) の名前と創立年を格納する Landmark 構造体を考えてみましょう。
struct Landmark { var name: String var foundingYear: Int }
Landmark の継承リストに Codable を追加すると、Encodable および Decodable からすべてのプロトコル要件を満たす自動準拠がトリガーされます。
struct Landmark: Codable {
var name: String
var foundingYear: Int
// Landmark now supports the Codable methods init(from:) and encode(to:),
// even though they aren't written as part of its declaration.
}
独自の型で Codable を採用すると、組み込みのデータ形式とカスタムエンコーダおよびデコーダが提供する任意の形式との間でシリアル化できます。たとえば Landmark 構造体は、PropertyListEncoder クラスと JSONEncoder クラスの両方を使用してコード化できますが、Landmark 自体にはプロパティリストや JSON を特別に扱うコードは含まれていません。
コード化可能な他のカスタム型で構成されたカスタム型にも同じ原則が適用されます。そのプロパティのすべてが Codable である限り、どのカスタム型も Codable にすることができます。
以下の例は、location (場所) プロパティが Landmark 構造体に追加されたときに自動 Codable 準拠性がどのように適用されるかを示しています。
struct Coordinate: Codable { var latitude: Double var longitude: Double } struct Landmark: Codable { // Double, String, and Int all conform to Codable. var name: String var foundingYear: Int // Adding a property of a custom Codable type maintains overall Codable conformance. var location: Coordinate }
Array、Dictionary、Optional などの組み込み型も、コード化可能な型を含む場合は常に Codable に準拠します。Landmark に Coordinate インスタンスの配列を追加すると、構造体全体が Codable を満たします。
以下の例は、Landmark 内に組み込みの codable 型を使用して複数のプロパティを追加する際に、自動準拠が適用される方法を示しています。
struct Landmark: Codable {
var name: String
var foundingYear: Int
var location: Coordinate
// Landmark is still codable after adding these properties.
var vantagePoints: [Coordinate]
var metadata: [String: String]
var website: URL?
}
排他的にコード化または復号する
場合によっては、Codable の双方向コード化と復号化のサポートが必要ない場合もあります。たとえば、一部のアプリでは、リモートネットワーク API を呼び出すだけで、同じ型を含む応答を復号する必要はありません。 データのコード化をサポートする必要がある場合のみ、Encodable への準拠を宣言します。逆に、与えられた型のデータのみを読み込む必要がある場合は、Decodable への準拠を宣言します。
以下の例は、データをコード化または復号するのみの Landmark 構造体の代替宣言を示しています。
struct Landmark: Encodable { var name: String var foundingYear: Int }
struct Landmark: Decodable { var name: String var foundingYear: Int }
コード化キーを使用してコード化および復号化するプロパティを選択
コード化可能な (Codable) 型は、CodingKey プロトコルに準拠する CodingKeys という名前の特別な入れ子になった列挙型を宣言できます。この列挙型が存在する場合、そのケースは、コード化可能な型のインスタンスがコード化または復号化されたときに含めなければならないプロパティの信頼できるリストとして機能します。列挙型 case の名前は、あなたの型の対応するプロパティに付けた名前と一致する必要があります。
インスタンスを復号化する時にそれらが存在しない場合、またはコード化された表現に特定のプロパティが含まれない場合は、CodingKeys 列挙体のプロパティを省略します。CodingKeys から省略されたプロパティーは、それが含む型が Decodable または Codable への自動的な準拠を受け取るために、デフォルト値が必要です。
シリアル化されたデータ形式で使用されるキーが、データ型からのプロパティ名と一致しない場合は、CodingKeys 列挙体の生の値型として String を指定して代替キーを指定します。それぞれの列挙かたの case の生の値として使用する文字列は、コード化および復号化時に使用されるキー名です。case の名前とその生の値の関連付けにより、あなたがモデル化しているシリアル化形式の名前、句読点、および大文字小文字と一致させるのではなく、Swift API 設計ガイドライン に従ってデータ構造体の名前を付けることができます。
以下の例では、コード化と復号化時に Landmark 構造体の name プロパティと foundingYear プロパティに代替キーを使用しています。
struct Landmark: Codable { var name: String var foundingYear: Int var location: Coordinate var vantagePoints: [Coordinate] enum CodingKeys: String, CodingKey { case name = "title" case foundingYear = "founding_date" case location case vantagePoints } }
手動でコード化と復号化
Swift 型の構造体がコード化された形式の構造体と異なる場合は、Encodable と Decodable のカスタム実装を提供して、独自のコード化と復号化のロジックを定義することができます。
以下の例では、Coordinate 構造体を拡張して additionalInfo コンテナの内部に入れ子にされた Elevation プロパティをサポートしています。
struct Coordinate { var latitude: Double var longitude: Double var elevation: Double enum CodingKeys: String, CodingKey { case latitude case longitude case additionalInfo } enum AdditionalInfoKeys: String, CodingKey { case elevation } }
コード化された Coordinate 型には第 2 レベルの入れ子にされた情報が含まれているため、この型の Encodable および Decodable プロトコルの採用では、特定のレベルで使用されるコード化キーの完全なセットをリストする 2 つの列挙型を使用します。
以下の例では、必須のイニシャライザ init(from:) を実装することによって、Coordinate 構造体を Decodable プロトコルに準拠するように拡張しています。
extension Coordinate: Decodable { init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) latitude = try values.decode(Double.self, forKey: .latitude) longitude = try values.decode(Double.self, forKey: .longitude) let additionalInfo = try values.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo) elevation = try additionalInfo.decode(Double.self, forKey: .elevation) } }
イニシャライザは、パラメータとして受け取る Decoder インスタンスのメソッドを使用して Coordinate インスタンスを生成します。Coordinate インスタンスの 2 つのプロパティは、Swift 標準ライブラリが提供するキー付きコンテナ API を使用して初期化されます。
以下の例は、必須メソッド encode(to:) を実装することにより、Coordinate 構造体を Encodable プロトコルに準拠するように拡張する方法を示しています。
extension Coordinate: Encodable { func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(latitude, forKey: .latitude) try container.encode(longitude, forKey: .longitude) var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo) try additionalInfo.encode(elevation, forKey: .elevation) } }
この encode(to:) メソッドの実装は、前の例の復号化操作を元に戻します。
コード化および復号化処理のカスタム化時に使用されるコンテナ型の詳細については、KeyedEncodingContainerProtocol および UnkeyedEncodingContainer を参照してください。
以下も見よ
カスタムのコード化と復号化
typealias Codable
外部表現に出入りできる型にそれ自身を変換することができる型。
protocol Encodable
外部表現にそれ自身をコード化できる型。
protocol Decodable
外部表現からそれ自身を復号できる型。
protocol CodingKey
コード化と復号化のキーとして使用できる型。
struct CodingUserInfoKey
コード化および復号化中にコンテキストを提供するためのユーザー定義キー。
関連した文書
Swift のさまざまな種類の JSON をコード化および復号化するためのアプローチを示します。