Help us understand the problem. What is going on with this article?

Realm移行時にStringly typedなAPIを回避する

More than 3 years have passed since last update.

iOS開発者にとって、Realmはそれまで敷居の高かったCore Dataと格闘するコストを削減してくれるDBライブラリです。

今やRealmはMobile Platformの導入により、iOS / Androidアプリ開発におけるDBのライブラリの代表格となっています。

Swift全般にも言えますが、Realmを使ってうれしいことは、strongly typed apiなので、
アクセスにおけるtypoが発生しないことです。

ですが、Objective-Cから存在するStringly TypedなAPIを使用する場面は発生してしまいます。僕が実際に遭遇したユースケースとその対処法を紹介します。

APIから取得したデータをRealmに保存する

あるAPIによって、jsonをレスポンスとして得たとき、そのレスポンスをそのままRealmに保存するとします。

Dictionaryにシリアライズして保存してもいいのですが、Stringly Typedになってしまうので、Himotokiなどの型安全なJSONデコーダをつかって、Realmオブジェクトにマッピングします。

変換したJSONを、RealmObjectのサブクラスに生やした下記のようなメソッドでRealmObjectに変換します。

class Sample:Object {

    func convert(from response: APIResponse.Hoge) {
        let realm = try! Realm()
        do {
                hoge = response.hoge
                fuga = response.fuga

            try realm.write {
                realm.add(self, update: true)
            }
        } catch {

        }
    }
}

Himotokiのdecodeでこれをやらないのは、常にRealmに保存するとは限らないからです。

これはみなさんもよく遭遇するユースケースだと思います。

DBとして用いられているUserDefaultsをRealmに移行する

UserDefaultsにDictionaryを入れて保存している場合がありますが、内部に一体何が保存されているのかわからないので、こういうものはとっととRealmにマイグレーションします。

上記と同じ例でいけそうです。

class Sample:Object {

    let hoge = RealmOptional<Int>()
    let fuga: String? = nil

    func converted(from data: [String : Any]) {
        let realm = try! Realm()
        do {
                hoge.value = data["hoge"]
                fuga = data["fuga"]

            try realm.write {
                realm.add(self, update: true)
            }
        } catch {

        }
    }
}

上記のユースケースなら遭遇する例も多く、また実装も難しいものではありません。RealmObject側をOptionalにしていますが、これはケースバイケースになると思います。

実際にあった怖い話:保存しているキーのTypo

これは実際にあった怖い話ですが、UserDefaultsに配列が保存されており、その内部がDictionaryになっているデータがありました。

こんなやつ

[
    { "images" : 
        [ 
            { "name" : "name" },
            { "name" : "name" }
        ]
    }
]

しかし、保存するメソッドが統一されておらず、キーのtypoによって、実際にはこんな感じになってました

[
    { "images" : //imagesが正しい
        [ 
            { "name" : "name" },
            { "name" : "name" }
        ]
    },
    { "image" ://typo!! 
        [ 
            { "name" : "name" },
            { "name" : "name" }
        ]
    }
]

このままではマイグレーションできません。マイグレーションする前に、キーは統一しておかなくてはなりません。

Dictionaryをdecodeする時に下記のような処理を通さざるを得ませんでした。Himotokiを使っています。

static func convert(from dictionary: [String : Any]){

    let images: [Image]? = {
        do {
            let images: [Image] = try e <|| "images"
            return images
        } catch {
            do {
                let images: [Image] = try e <|| "image"
                return images
            } catch {
                return nil
            }
        }
    }()
}

このような事故が起こらないように、日頃からStrongly TypedなAPIを使うように心がけたいですね。

結論

他にも古いプロジェクトでは、SQLiteから移行する場合等もあると思いますが、基本的には、RealmObjectのサブクラスにマッピング用のメソッドを生やすのがよさそうです。

Stringly Typed APIは良くないので、Strongly TypedなAPIになるように作り変えていきましょう。

参考資料

今回の内容はtrySwift!NYCでAndyy Hopeさんが発表されていたお話をRealm周辺で適応するとどうなるかという話でした。僭越ながら、Realmでこの講演の日本語への翻訳を担当させていただきましたので、ぜひこちらもお読みください。

Swift Eye for the Stringly Typed API(日本語)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした