Realm
Realm Database とは
基本
code:swift
class User: Object {
@objc dynamic var name = ""
@objc dynamic var age = 0
}
code:swift
let realm = try! Realm()
// クエリ
let users = realm.objects(User.self)
// 書き込み
let u = User()
try! realm.write {
realm.add(u)
}
// 更新
DispatchQueue(label: "background").async {
autoreleasepool {
let realm = try! Realm()
let theUser = realm.objects(User.self).filter("age == 1").first
try! realm.write {
theUser!.age = 3
}
}
}
モデル定義
Object.primaryKey()
Realm のモデルは struct ではなく class である。これは、Realm の扱うモデルは値ではなく、Realm 内のデータを参照しているオブジェクトであるため。これにより、常に最新の値を参照することができるようになっている。
概念
Realm コンテナ
Realm は、Realm データベースを抽象化したコンテナ。書き込み先の設定はこのコンテナに Configuration として注入する。実際のデータの読み書きもこのコンテナを介して行う。 あるスレッドにおいて Realm コンテナを一度作成すると、その後は一度作成されたインスタンスがキャッシュされて使いまわされる。この最初の一度目のみコンテナの作成に失敗する場合がある。
code:swift
// デフォルトだと、Documents ディレクトリ以下に default.realm ファイルとしてデータを永続化する
let realm = try! Realm()
// 保存先は Configuration 変更可能
let config = Realm.Configuration(
fileUrl: Bundle.main.url(forResource: "MyData", withExtension: "realm"),
readOnly: true
)
let realm = try! Realm(configuration: config)
// ディスク上ではなくメモリ上に保存することも可能
let config = Realm.Configuration(inMemoryIdentifier: "MyIdentifier")
let realm = try! Realm(configuration: config)
Model
Realm のモデルは、Object クラスを継承した Swift クラスとして定義する必要がある。Realm は起動時にコード上の Realm モデル定義を、利用されている, いないにかかわらず 全てパースし validation するため、全てのモデル定義は正しく行われている必要がある。 データ型
サポートされている型は以下。
真偽値:
Bool
数値:
Int, Int8, Int16, Int32, Int64, Double, Float
文字列:
String
日付:
Date
データ:
Data
他の Realm モデル
列挙型:
RealmEnum
これらのうち、文字列, 日付, データ 型のみ、Optional 型をサポートしている。数値, 真偽値を Optional で保存するためには RealmOptional クラスをコンテナとして利用する。 Enum はサポートしていないが、@objc を付与して定義された enum は、RealmEnum として保存できるようだ。 code:swift
class Person: Object {
@objc dynamic var name: String = ""
// String の場合は Optional をそのままサポートしている
@objc dynamic var nameOptional: String? = nil
@objc dynamic var age: Int = 0
// 数値の場合は RealmOptioanl でラップする
let ageOptional = RealmOptional<Int>()
}
主キーやインデックスは、static メソッドをオーバーライドすることで指定できる。
code:swift
class Person: Object {
@objc dynamic var id = 0
@objc dynamic var name = ""
override static func primaryKey() -> String? {
return "id"
}
}
class Book: Object {
@objc dynamic var price = 0
@objc dynamic var title = ""
override static func indexedProperties() -> String { }
}
class Person: Object {
@objc dynamic var tmpID = 0
var name: String { // read-only properties are automatically ignored
return "\(firstName) \(lastName)"
}
@objc dynamic var firstName = ""
@objc dynamic var lastName = ""
override static func ignoredProperties() -> String { }
}
関連
code:swift
// n:1
class Dog: Object {
@objc dynamic var owner: Person?
}
// n:n
class Person: Object {
let dogs = List<Dog>()
}
// 逆方向の関連
class Dog: Object {
let owners = LinkingObjects(fromType: Person.self, property: "dogs")
}
Migration
結構複雑なマイグレーションでもなんとかできる。
Notifications
Realm の通知は iOS の run loop を利用する。3つのレベルがある
Object Level
Realm オブジェクトのプロパティの変更を監視する
Collection Level
List 等のコレクションの変更を監視する
Realm Level
realm ファイル全体の変更を監視する
注意点
Migration時に古いテーブル定義を消すことができない
Primitive な List への migration ができない
List への migration はできる
が、Primitive な List への migration 方法はわからなかった