# エンコードとデコード

Swiftでは、データを保存してネットワーク経由で送信する前に、エンコード やシリアライズと呼ばれるプロセスを経て、データを適切な形式に変換する必要があります。

また、ネットワークを介して送信されたデータをプログラムで使用する前に、適切な形式に変換する必要があります。この逆の処理を デコード またはデシリアライズと呼びます。

# Data型

Data型 は、メモリ上のバイト列を管理するため構造体です。Foundationフレームワークが提供しているので、Data型を使うにはFoundationをimportする必要があります。

Data型はさまざまなデータの表現に使用され、ファイルやURLを指定してデータを読み込んだり、メモリのデータをファイルに書き出したりできます。また、画像やJSONを表現する場合などにも使われます。

# JSON

一般的に、アプリがAPIサーバーと通信する場合、データはJSON形式でやりとりすることが多いかと思います。Foundationフレームワークの JSONEncoder クラスを使用すると、Swiftの値をJSONに変換することができ、JSONDecoder クラスはJSONをSwiftの値にデコードすることができます。

# JSONEncoder

JSONEncoder はSwiftの値をJSONに変換します。変換されるSwiftの値は Encodable プロトコルに準拠する必要があります。

次の例では、JSONEncoder クラスのインスタンスを生成して、.encode メソッドを呼び出して変換しています。変換されるUser型は、Encodable プロトコルに準拠させます。

最後では、実行結果を見るために、エンコードされたバイト列のData型をString型にして表示しています。

import Foundation

// JSONEncoder クラスのインスタンスを生成
let encoder = JSONEncoder()

// Encodableプロトコルに準拠させる
struct User: Encodable {
  let id: String
  let name: String
}

// Swiftの値をJSON形式にエンコードしてData型として受け取る
let user1 = User(id: "1", name: "Taro")
let encodedData = try encoder.encode(user1)

// JSONの中身を見るためにData型を文字列に変換
let json = String(data: encodedData, encoding: .utf8)!
print(json)

/* 実行結果 */
// {"id":"1","name":"Taro"}

# JSONDecoder

JSONDecoder はJSONをSwiftの値に変換します。変換される値は Decodable プロトコルに準拠する必要があります。

.decode メソッドには、型名とデコードするData型を指定します。

JSONDecoder().decode(型.self, from: デコード対象のData型)

次の例では、エンコードされたバイト列のJSONデータをUser型にデコードしています。User型は、デコードされるために Decodable に準拠しています。

import Foundation

let encoder = JSONEncoder()

// Decodableに準拠
struct User: Encodable, Decodable {
  let id: String
  let name: String
}

let user1 = User(id: "1", name: "Taro")
let encodedData = try encoder.encode(user1)


// JSONDecoder クラスのインスタンスを生成
let decoder = JSONDecoder()

// デコードする
let decoded = try decoder.decode(User.self, from: encodedData)

print(decoded)

/* 実行結果 */
// User(id: "1", name: "Taro")

デコードされる対象はData型でないといけないので、JSON形式の文字列を直接指定してもコンパイラはエラーを出力します。

import Foundation

struct User: Encodable, Decodable {
  let id: String
  let name: String
}

let decoder = JSONDecoder()

// JSON形式の文字列を指定する
let decoded = try decoder.decode(User.self, from: "{\"id\": \"1\", \"name\": \"Taro\"}")

/* 実行結果 */
// error: cannot convert value of type 'String' to expected argument type 'Data'

次のように、文字列をData型に変換させる必要があります。

import Foundation

struct User: Encodable, Decodable {
  let id: String
  let name: String
}

let decoder = JSONDecoder()

// JSON形式の文字列を指定する
let decoded = try decoder.decode(User.self, from: "{\"id\": \"1\", \"name\": \"Taro\"}".data(using: .utf8)!)

print(decoded)

/* 実行結果 */
// User(id: "1", name: "Taro")