Swift4 の Codable

Codable は クラスと構造体(struct)に追加された Swift4 の新しいプロトコルで、これを利用すると Data 型から構造体やクラスを生成することがとても簡単になります。

APIを利用するアプリケーションでは、GET でサーバから JSON を受け取ってモデルを生成したり、逆に POST や PUT でデータを作成・更新するときはモデルから JSON を生成する、ということをよくすると思いますが、Codable を利用するとどういう風にかけるのかをご紹介します。

JSON → Data → クラス(構造体)

// サーバから受け取った JSON
let api: [String: Any] = ["name": "Suzuki", "age": 10]

// JSON を Data に変換します
let data = try! JSONSerialization.data(withJSONObject: api, options: [])

// Data から生成するクラスを定義します
class User: Codable {
    let name: String
    let age: Int
}

// Data からクラスを生成します
// JSON のキーと同名の プロパティ に自動的に値をセットします
let user = try! JSONDecoder().decode(User.self, from: data)

// プロパティにアクセスできるか確認してみましょう
print(user.name) // "Suzuki"
print(user.age) // 10

JSON のキー名とクラスのプロパティ名が違う場合

CodingKeys という enum を定義してバインディングします。たとえば上記の API で「name」が「username」になっていて、それを User モデルの name プロパティにセットするには以下のようにします。

class User: Codable {
    let name: String
    let age: Int
    
    enum CodingKeys: String, CodingKey {
        case name = "username"
        case age
    }
}

バインディング対象じゃないプロパティもすべて enum の case に書く必要があるので少しめんどうです。

クラス(構造体) → Data → JSON

// クラス を Data に変換します
let data = try! JSONEncoder().encode(user)

// Data を JSON に変換します
let json = try! JSONSerialization.jsonObject(with: data, options: [])
if let json = json as? [String: Any] {
    print(json["name"] as! String) // "Suzuki"
    print(json["age"] as! Int) // 10
}