【SwiftUI】Realmの@ObservedRealmObjectの使い方やメリットと違い!
この記事からわかること
- Swiftでデータを永続的に
保存 する方法 - Realmで値の変更を観測する方法
- @ObservedRealmObjectの使い方
- @ObservedResultsとの違い
index
[open]
\ アプリをリリースしました /
iOSアプリのデータを永続的に保存する目的で使用されるデータベース「Realm(レルム)」で値の変更を観測する@ObservedRealmObjectの使い方をまとめていきます。
Realmの使い方や導入方法に関しては以下の記事を参考にしてください。
参考文献: React to Changes - SwiftUI
@ObservedRealmObject:オブジェクトを観測
公式リファレンス:ObservedRealmObject - SwiftUI
@ObservedRealmObjectはRealm Swiftライブラリで使用できるプロパティーラッパーの1つです。
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper
public struct ObservedRealmObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject, ObjectType : RealmSubscribable, ObjectType : ThreadConfined, ObjectType : Equatable
@ObservedRealmObjectを使用することでオブジェクトまたはRealmSwift.List<Element>を観測することができます。
使用するのは親ビューからRealmオブジェクトを受け取る子ビューに対して使用します。
使い方
今回は以下のようなテーブルクラスが定義されている場合の使用方法を見ていきます。大元となるUserGroupクラスにはList型でUser型の値を保持するのプロパティを定義しています。
テーブル定義
class User: Object,ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var id: ObjectId
@Persisted var name:String = ""
@Persisted var age:Int = 0
}
class UserGroup: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var id: ObjectId
@Persisted var users = RealmSwift.List<User>()
}
親ビューから子ビューへ渡す
親ビューではRealmデータベースからデータを取得するために@ObservedResultsを使用してResults<UserGroup>形式で取得します。@ObservedResultsを使って取得したデータは$を付与することで削除や追加が可能になりますが親ビューでは使用しません。
ここでは子ビューに対して取得したRealmオブジェクト(Groupレコード1件)を渡しています。
親ビュー
struct ContentView: View {
@ObservedResults(UserGroup.self) var groups
var body: some View {
if let group = groups.first{
ChildView(group:group)
}
}
}
子ビューから孫ビューへ渡す
子ビュー側で親ビューから渡されたRealmオブジェクトを@ObservedRealmObjectを付与したプロパティでキャッチします。これにより子ビュー側でも$を付与して削除や追加が可能になります。@ObservedRealmObjectを付与していない場合は$によるバインディングが使用できません。
ここではさらに孫ビューへとRealmオブジェクト(List<User>内のUserレコード1件)を渡しています。
子ビュー
struct ChildView: View {
@ObservedRealmObject var group:UserGroup
var body: some View {
List {
ForEach(group.users) { user in
RowUserView(user: user)
}.onDelete(perform: $group.users.remove)
}.listStyle(GroupedListStyle())
}
}
孫ビューからデータベースを操作する
孫ビューでは受け取ったUser型のレコードを表示させています。ここからデータベースの値を更新したい場合は@ObservedRealmObjectが凍結されているのでwriteメソッドが使えない点に注意しなければいけません。
解凍するにはthawメソッドを呼び出します。これでタップされた時にageプロパティの値を更新することが可能になります。(意味のないコードですが...)
孫ビュー
struct RowUserView: View {
@ObservedRealmObject var user:User
var body: some View {
HStack{
Text(user.name)
Text("\(user.age)")
}.onTapGesture {
let thawUser = user.thaw()
try! thawUser?.realm!.write{
thawUser?.age = 100
}
}
}
}
とはいえ孫ビューに関しては@ObservedRealmObjectを付与しなくても期待通りに動作したので@ObservedRealmObjectのメリットは$を使ったバインディングなどが子ビューでも実装できるようになること?
@ObservedResultsとの違い
同じようなRealmのプロパティラッパーに@ObservedResultsがあります。両者の違いを見るために特徴をまとめてみます。
| データの取得 | 使用ビュー | 観測対象 | |
|---|---|---|---|
| @ObservedResults | テーブルからフェッチ | 親ビュー | Results<Element> |
| @ObservedRealmObject | 親ビューから受け取る | 子ビュー | オブジェクト or RealmSwift.List<Element> |
@ObservedResultsはRealmデータベースを直接参照してデータを取得するのに対して、@ObservedRealmObjectはビューの引数として受け取る前提ということでしょうか?
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。
私がSwift UI学習に使用した参考書
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。





