【SwiftUI】Realmの@ObservedRealmObjectの使い方やメリットと違い!
この記事からわかること
- Swiftでデータを永続的に
保存 する方法 - Realmで値の変更を観測する方法
- @ObservedRealmObjectの使い方
- @ObservedResultsとの違い
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
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学習に使用した参考書
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。