Swift

UserDefaultsへのCodableの保存とmigration

こんにちは!リードエンジニアの@Utmrerです!ヴァイオレット・エヴァーガーデンが楽しみ過ぎて早く年越したいと毎日思っています。
この記事はコネヒト Advent Calendar 2017の18日目の記事です。

今日はCodableについて書くのですが、Swift4に追加されたCodableはとても便利で、JSONを構造体にマッピングするために使っている方が多いと思います。
Codableに準拠すればDataクラスへの変換を挟むことでUserDefaultsへ保存することができ、弊社では一部のデータモデルでその処理を行っています。
この記事ではUserDefaultsへのI/Fをサッと説明して、データモデルの変更(migration)についてもサッと説明します。

UserDefaultsへのCodableの保存

それではまずidnameを持つUserをCodableに準拠して定義します。

User.swift
struct User: Codable {
    let id: Int
    let name: String
}

ではUserDefaultsに保存してみましょう。

let user = User(id: 1, name: "violet")
let data = try? JSONEncoder().encode(user)
UserDefaults.standard.set(data, forKey:"auto_memories_doll")

簡単ですね。では取り出してみましょう。

guard let data = UserDefaults.standard.data(forKey: "auto_memories_doll") else {
    return
}
let user = try? JSONDecoder().decode(User.self, from: data)

簡単ですね。Decodeに失敗した時はnilになります。

Userを変更する(migration)

ではここでUserに年齢を表すageを追加したくなったとします。

User.swift
struct User: Codable {
    let id: Int
    let name: String
    let age: Int
}

このようにデータモデルが変更された時、UserDefaultsには変更される前の情報しか無く、Optionalではないageの情報がないためUserDefaultsから以前保存したUserを取得出来なくなってしまいます。

// ageを追加しただけだと`user`がnilになっちゃう
let user = try? JSONDecoder().decode(User.self, from: data)

以前保存したid=1, name=violetというデータを失いたくない時はDecodableに定義されているinit(from decoder: Decoder)を実装してあげましょう。
「UserDefaultsに保存されていない」が「ageはOptionalではない」ので、下記のように初期値を与えてあげるといいでしょう。

User.swift
struct User: Codable {
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case age
    }

    let id: Int
    let name: String
    let age: Int

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        id = try values.decode(Int.self, forKey: .id)
        name = try values.decode(String.self, forKey: .name)
        age = (try? values.decode(Int.self, forKey: .age)) ?? 0
    }
}

まとめ

以前、自分のブログでSwift4のCodable(Decodable)でStringの値をIntにcastするというのを書いたのですが、Codableは「ちょっと頑張れば痒い所に手が届く」って感じですね。
以上、田村でした!明日は@super_mannerの「API Client ToolのPawのExtension周りの話」かもしれないし、違うかもしれません!
良いお年を!

コネヒト Advent Calendar 2017