24
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Swift】避けてきたRealm migrationを学ぶ。

Last updated at Posted at 2020-07-06

こんにちは。いるべさんです。

経緯

アプリを作るとき、とてもお世話になるローカルデータベース。
リリース前の開発段階ではDBの構成を変えて不整合エラー出してもリセットして逃げて乗り越えてきた。

ただ、リリース後にそんなことしてユーザ様に「ローカルデータ捨ててインストールし直してくださいよw」なんて言えないのでコチラが譲歩する。(やれやれ。)

ということで

その為にマイグレーションを行う。
書き方を知ればとても簡単なので、いるべさんはこの記事に残す。

準備!

ネコちゃん

今回はネコちゃんのデータをこねくり回す。
最初は名前と年齢を持っておくだけ。

CatRealm.swift
class Cat: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
}

データ保存

ここは今回の本筋では無いのでさらーっと。

ViewController.swift
let realm = try! Realm()

let mofu = Cat()
mofu.name = "たぬ"
mofu.age = 5

try! realm.write() {
    realm.add(mofu)
}

うちにはタヌキみたいな見た目のモフモフしたネコがいる。
カワイイ。
「だから」たぬちゃんのデータを保存しておく。写真みたいなもんだ。

リネームしてみる。

ネコも家族。

まず変数名を変更してみる。
nameプロパティをfullNameに変更する。

CatRealm.swift
class Cat: Object {
    @objc dynamic var fullName = ""
    @objc dynamic var age = 0
}

この時点・この状態で実行してみる。

もちろん不整合エラー

↓↓↓↓↓解決策

マイグレーション

マイグレーションを行う。

コードスラスラ読めないマンからすると「うっ!」となるコードですが、、
ほとんどこのまま流用できるので最初は脳死で使いましょう!!!

Realm.swift

func migration() {
    Realm.Configuration.defaultConfiguration = Realm.Configuration(
        schemaVersion: 1, // ①
        migrationBlock: { migration, oldSchemaVersion in
            if(oldSchemaVersion < 1) {
                migration.renameProperty(onType: Cat.className(), from: "name", to: "fullName") //②
            }
       }
    })
}

大事なのは①schemaVersionと②migration.renamePropertyの行だけ。

  • ①のschemaVersionは何も変更していなければ最初は0なので、初回変更時は1に設定する。

  • 変更するたびに1ずつインクリメントすることでマイグレーションを行える。

  • schemaVersionはUInt型なので1.4みたいなバージョンは指定できない。

  • 例えばschemaVersionに一度例えば5を指定してマイグレーション後、3など5より下に指定するとエラー

今回はnameをfullNameに変更するので
renamePropertyのfromに変更前のプロパティ名。
toに変更後のプロパティ名を入れれば変更できる。

ViewController.swift
let realm = try! Realm()
var mofu = realm.objects(Cat.self).first
try! realm.write {
    mofu.fullName = "いるべ" + mofu.fullName
}

確かめる。

上のmigration関数をCatを読み出す前に実行させる。
→ しないと不整合エラー

Catの情報を見てみると、

Results<Cat> <0x7f9ca7809210> (
	[0] Cat {
		fullName = "いるべたぬ";
		age = 5;
	}
)

たぬもこれで家族の一員だとハッキリする。

プロパティを追加&削除する。

種類も覚えておきたい。

ラグドールって聞いたことありますか?
あんまり聞かないよなぁと思うので種類のデータも保存しましょう!

あと、たぬは女の子なので年齢は隠します。(今更)

CatRealm.swift
class Cat: Object {
    @objc dynamic var fullName = ""
    @objc dynamic var kind = "ラグドール"
}

初期値にうちのたぬの種類:「ラグドール」を入れておく。
!実際にはこんなに具体的な初期値を入れるのはお勧めしません〜。

マイグレーションする!

Realm.swift
Realm.Configuration.defaultConfiguration = Realm.Configuration(
    schemaVersion: 2,
    migrationBlock: { migration, oldSchemaVersion in
        if(oldSchemaVersion < 2) {
            migration.enumerateObjects(ofType: Cat.className()) { _, _ in
                // pass: 何もいらない
            }
        }
    }
})

2回目の変更なので前回のschemaVersionに1プラスすることが大事。

確かめる。

Results<Cat> <0x7f9ca7809210> (
	[0] Cat {
		fullName = "いるべたぬ";
		kind = "ラグドール";
	}
)

プロパティの追加、削除は元のオブジェクトクラスにプロパティを追加してマイグレーションを行うだけ。思ってたよりずっと簡単なんだなぁと思った。

前のデータを利用する。

kindが何となく邪魔になったので名前と合体させることにした。
もはやうちのたぬが可愛いだけの実用性のないオブジェクトになっていくのは目を瞑りましょう。

タス、ケテ、、

CatRealm.swift
class Cat: Object {
    @objc dynamic var nameAndKind = ""
}

実際にこんなプロパティは作らないでくださいというアンチパターン!!!
流石に誰もこんなことしないか。笑

Realm.swift
Realm.Configuration.defaultConfiguration = Realm.Configuration(
    schemaVersion: 3,
    migrationBlock: { migration, oldSchemaVersion in
        if(oldSchemaVersion < 3) {
            migration.enumerateObjects(ofType: Cat.className()) { old, new in
                new!["nameAndKind"] = old!["fullname"] + ":" + old!["kind"]
            }
        }
    }
})

migration.enumerateObjectsの、oldとnewについて

  • oldは変更前のname, ageを持ったCatオブジェクト。
  • newは変更後のfullName, ageを持ったCatオブジェクト。

これだけで新しいプロパティを追加できる。

確かめる。

Results<Cat> <0x7f9ca7809210> (
	[0] Cat {
		nameAndKind = "いるべたぬ:ラグドール";
	}
)

一個前の削除も同時に行われて救いようがない、もしくは救うのがめんどくさいオブジェクトができました!

いるべさんと学ぶカンタンマイグレーションでした。

ここまでお読み頂きありがとうございました。

24
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?