【ISSUE】[Swift5] Realmのよく使うところだけをサンプル付きでまとめてみた

0

2024年12月23日 17:28

Realm

概要

  • 保存できる型

    • Bool, Int, Int8, Int16, Int32, Int64, Double, Float, String, Date, Data.
  • CGFloatで保存することは推奨されない(できなくはないが型がRealmで保証されていない)

  • String, Date, DataOptional指定 が可能。
    その他の保存できる型で Optional指定 をしたい場合は、RealmOptionalを利用する。RealmOptionalは「Int, Float, Double, Bool」に対応。
    RealmOptionalプロパティは必ずletでなければいけない。

RealmDatabaseの作成(CREATE DATABASE)

img

RealmDatabaseの削除(DROP DATABASE)

img

モデルの定義(CREATE TABLE)

img

モデルの継承

img

モデルプロパティの属性

Realmモデルに定義されるプロパティは@obj dynamic var属性を持たなければならない。ただしSwift4以降で利用することのできる@objcMembers修飾子をクラスに宣言している場合、プロパティは単にdynamic var属性で宣言することができる。

img

ただし、LinkingObjects, List, RealmOptional属性は動的なプロパティとして宣言することができないので、常にletで宣言しなければならない。

TypeNon-optionalOptional
Bool@objc dynamic var value = falselet value = RealmOptional<Bool>()
Int@objc dynamic var value = 0let value = RealmOptional<Int>()
Float@objc dynamic var value: Float = 0.0let value = RealmOptional<Float>()
Double@objc dynamic var value: Double = 0.0let value = RealmOptional<Double>()
String@objc dynamic var value = ""@objc dynamic var value: String? = nil
Data@objc dynamic var value = Data()@objc dynamic var value: Data? = nil
Date@objc dynamic var value = Date()@objc dynamic var value: Date? = nil
Objectn/a@objc dynamic var value: Class?
Listlet value = List<Type>()n/a
LinkingObjectslet value = LinkingObjects(fromType: Class.self, property: "property")n/a

プライマリキー

モデルを定義する時に primaryKeyメソッドをオーバーライドすることで、モデルの主キーを設定することができる。主キーを設定したオブジェクトをRealmに保存すると、後から変更することができない。

img

インデックス

Realmでは各モデルでプロパティのインデックスをindexedPropertiesメソッドをオーバーライドすることで作成できる。インデックスを作成することで、等号演算、IN演算しを用いたクエリを高速に実行することができる。(※ インデックスを作成するため Realmファイルのサイズは大きくなる)

RealmではString, Int, Bool, Date型プロパティのインデックスに対応している。

img

プロパティの無視

Realmに保存する必要のない変数(一時使用、一時的な変数)をignoredPropertiesメソッドをオーバーライドすることで設定できる。これを設定することでプロパティとして操作、利用することができるが、保存する際にデータは無視される。また、getterしか持たない変数は、自動的にモデル保存時に無視される。

img

モデルの書き込み

モデルを書き込むためには、モデルオブジェクトをインスタンス化してRealmに追加する必要がある。

img

  1. オブジェクトのインスタンスを生成した後、直接プロパティに対して値を代入して作成する方法
  2. オブジェクトをインスタンス化する際にDictionaryを用いて、初期化して作成する方法
  3. オブジェクトをインスタンス化する際にArrayを用いて、初期化して作成する方法
    (※ この場合、配列内要素の並びはモデルのプロパティ並びと同じでなければならない。またモデル保存時に無視されるプロパティやgetterのみのプロパティなどは無視する必要がある)

モデルオブジェクトを作成後、Realmに追加することができる。

img

Realmへの書き込みトランザクションが終了すると、他のスレッドでも追加した値を利用することができるようになる。このとき、複数の書き込みが同時進行で発生した場合は、他方の書き込みが終わるまでロックされる。これによって書き込みがロックされているスレッドもロックされることを注意する必要がある。

ただし、書き込みトランザクションが終了していない場合であっても、読み込みは可能である。

モデルの更新

モデル更新の方法は複数ある。

img

img

プライマリキーを設定している場合は、プライマリキーによる更新を行うことができる。

img

この時、主キー(id: 1)がすでに存在していれば単に更新処理が走る。主キーが存在しない場合は create と同等の処理が実行される。また、主キーと更新したい値のサブセットを引数にすることで差分更新を行うことができる。

img

ただし、主キーを定義していないモデルオブジェクトを更新する場合には update: の引数に .modified, .all を渡すことができない。また、.modified, .allを使った多重(コンフリクトが発生するような)書き込みの結果には注意が必要。

img

この場合、2つの更新が同時に発生するためコンフリクトが発生する。これらの書き込みがマージされた結果として得られる結果は、以下のどちらかとなる。

img

しかしupdate: .modifiedとした場合は、挙動が変わる。

img

この場合の書き込みがマージされた結果は以下のようになる

img

.all は完全置き換え、.modified は差分置き換えであることを注意する必要がある。

モデルの削除

書き込みトランザクションの中で以下を実行する。

img

モデルの変更通知

Realmのオブジェクトインスタンスは自動的に更新される。つまり、オブジェクトのプロパティを変更すると、同じオブジェクトを参照している他のインスタンスに、その変更が即座に反映される。Realmオブジェクトの更新通知を購読することで、対象のRealmオブジェクトに変更があった場合に通知を取得できる。

img

モデル間のリレーション

  • 1:N, N:1

img

  • 双方向リレーション
    一般的にモデル同士のリレーションはリンクされてる側からインスタンスを参照することはできるが、逆方向からは辿ることができない。RealmではLinkingObjectsを用いることで、双方向リレーションを形成することができる。LinkingObjectsは特定のプロパティ(ここではPersonモデルのdogsプロパティ)から与えられたオブジェクトにリンクされているすべてのオブジェクトを取得することができる。

img

Appendix

JSONによるRecord作成

Realm は直接JSONをサポートしていないが、JSONSerialization の出力を用いでオブジェクトを生成することができる。JSON内にネストされてるオブジェクトや配列は、自動的にリレーションにマッピングされることに注意する必要がある。

この方法でオブジェクトを生成するときには、いくつかの注意点が存在する。

  • オブジェクトのプロパティ名とJSONのキー名が一致して、型が同じである必要があります。

  • floatプロパティは、floatをバックにしたNSNumbersで初期化する必要があります。

  • DateプロパティとDataプロパティは文字列から自動的に推論することはできませんが、Realm().create(_:value:update:)に渡す前に適切な型に変換しなければなりません。

  • 必須プロパティに JSON NULL (すなわち NSNull) が与えられた場合、例外がスローされます。

  • insert 時に必須のプロパティが与えられない場合は、例外がスローされます。

  • Realmは、Objectで定義されていないJSON内のプロパティを無視します。

img

モデルオブジェクト更新時の設定

Realm では Realm に書き込まれたか否かで、更新方法が変わる場合がある。

  • アンマネージドオブジェクト

Realm に書き込まれる前のオブジェクト( realm.write クロージャーの外でプロパティを変更できる)

  • マネージドオブジェクト

Realm に書き込まれた後のオブジェクト (realm.write クロージャーの外でプロパティを変更できない)

img

一般的には、このように分離して処理を変更するべきであるが、以下のようにすることもできる。

img

[cv:issue_marketplace_engineer]

0

診断を受けるとあなたの現在の業務委託単価を算出します。今後副業やフリーランスで単価を交渉する際の参考になります。また次の単価レンジに到達するためのヒントも確認できます。