MILLEN BOX 2

個人iOSアプリ開発者hollymotoによる勉強の記録。時々雑記。

Realm Swiftの使い方メモ

モバイルデータベースであるRealmのSwiftでの使い方メモです。随時更新予定です。

目次

1. import RealmSwift

Realmを使用したいswiftファイルでRealmSwiftをインポートしましょう。

import Foundation
import RealmSwift  //コレ

2. モデルの定義とデータの永続化、取得の基本

犬モデルを以下ように定義したとします。(Realmのサイトのチュートリアル的なやつも参考に。)

// Dog model
class Dog: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
}

したいこと

  1. この犬モデルを使用して「僕の初めての犬」を具現化
  2. Realmでデータを保存し永続化
  3. Realmから保存したデータを取得
  4. 取得したデータの内容を簡易確認

このコードは以下のようになります。

import UIKit
import RealmSwift

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //練習1
        realmTraining1()
    }
    
}

extension ViewController {
    //練習1
    func realmTraining1() {
        //Realmオブジェクトを作っとく
        let realm = try! Realm()

        //犬モデルに基づき「僕の初めての犬」オブジェクトを作成
        let myFirstDog = Dog()
        myFirstDog.name = "ポチ"
        myFirstDog.age = 1
        
        //Realmオブジェクトに犬(一匹目)オブジェクトを追加しデータを永続化
        try! realm.write {
            realm.add(myFirstDog)
        }
        
        //Realmオブジェクトに保存してある犬モデルのオブジェクトを全取得
        let allDogs = realm.objects(Dog.self)
        
        //取得できているかprintで確認
        print(allDogs)
        
    }
}

3. 関連するモデルの定義(1対1の場合)

2で定義したモデルと紐付けされた「人」(ひいては飼い主)モデルを作った場合、以下のようになる。関連付けは人→犬で一方的。

//Realm公式チュートリアル
// Person model
class Person: Object {
    @objc dynamic var name = ""
    @objc dynamic var birthdate = Date(timeIntervalSince1970: 1)
    @objc dynamic var dog: Dog?
}
// Dog model
class Dog: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
    @objc dynamic var owner: Person?
}
import UIKit
import RealmSwift

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //練習2
        realmTraining2()
    }
    
}

extension ViewController {
    
    //練習2
    func realmTraining2() {
        //Realmオブジェクトを作っとく
        let realm = try! Realm()
        
        //犬モデルに基づき「僕の初めての犬」オブジェクトを作成
        let myFirstDog = Dog()
        myFirstDog.name = "ポチ"
        myFirstDog.age = 1
        
        //人モデルにも基づき「飼い主圭一」オブジェクトを作成
        let ownerKeichi = Person()
        ownerKeichi.name = "圭一"
        ownerKeichi.dog = myFirstDog
        
        //Realmオブジェクトに犬(一匹目)オブジェクトを追加しデータを永続化
        try! realm.write {
            realm.add(ownerKeichi)
        }
        
        //Realmオブジェクトに保存してある犬モデルのオブジェクトを全取得
        let allDogs = realm.objects(Dog.self)
        
        //取得できているかprintで確認
        print(allDogs)
        
    }
}

出力

Results<Person> <0x7fb41402d0e0> (
    [0] Person {
        name = 圭一;
        birthdate = 1970-01-01 00:00:01 +0000;
        dog = Dog {
            name = ポチ;
            age = 1;
        };
    }
)

4. 逆方向の関連付けモデルの定義方法

3の関連付けの例では人→犬へ関連付けはされていますがその結果、人→犬への関連付けが自動でされることはありません。その証拠に練習2に以下のコードを付け足してみて実行してみて下さい。

ownerプロパティ確認コード

        //Realmオブジェクトに保存してある犬モデルのオブジェクトを全取得
        let allDogs = realm.objects(Dog.self)
        
        //取得できているかprintで確認
        print(allDogs.first!.owner)

結果はnilになり、何も自動で入らないことがわかります。 自動で関連付けさせるためにはどうしたらいいのでしょうか?例えば今まで使用してきたDogモデルのownerプロパティを以下のように変更してみて下さい。

// Person model
class Person: Object {
    @objc dynamic var name = ""
    @objc dynamic var birthdate = Date(timeIntervalSince1970: 1)
    @objc dynamic var dog: Dog?
}
// Dog model
class Dog: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
    let owner = LinkingObjects(fromType: Person.self, property: "dog")  //コレ
}

LinkingObjectsはそのプロパティを参照した時に、関連付けられてモデルを引っ張ってきてくれるような仕組みになっています。

このモデルにて先の練習2のコード+ownerプロパティ確認コードを実行した結果、以下のようになりdogの中のPerson型のownerプロパティが参照可能になっていることから、自動で逆方向の関連付けが取得可能になっていることがわかります。

実行結果

LinkingObjects<Person> <0x7f8f7a40f940> (
    [0] Person {
        name = 圭一;
        birthdate = 1970-01-01 00:00:01 +0000;
        dog = Dog {
            name = ポチ;
            age = 1;
        };
    }
)

5. 実装中にモデルを変更→実行時にクラッシュする場合

通常、一度保存したデータベースのモデルに対しプロパティを増やすような変更した場合、クラッシュして落ちます。こうゆう時は一先ずマイグレーション対応をしてお茶を濁しましょう。

var config = Realm.Configuration()
config.deleteRealmIfMigrationNeeded = true
let realm = try! Realm(configuration: config)

6. List(Objectを格納する配列型)のItemの順番の入れ替え方法

let realm = try! Realm()
let tapDateList = realm.objects(TapDateList.self).first!.list  //Listを取得
try! realm.write {
    tapDateList.swapAt(fromIndexPath.row, to.row)   //write内で入れ替えを実行
}