【SwiftUI】Realmの@ObservedRealmObjectの使い方やメリットと違い!

この記事からわかること

  • Swiftデータ永続的保存する方法
  • Realm変更観測する方法
  • @ObservedRealmObject使い方
  • @ObservedResultsとの違い

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

iOSアプリのデータを永続的に保存する目的で使用されるデータベース「Realm(レルム)」で値の変更を観測する@ObservedRealmObjectの使い方をまとめていきます。

Realmの使い方や導入方法に関しては以下の記事を参考にしてください。

参考文献: React to Changes - SwiftUI

@ObservedRealmObject:オブジェクトを観測

公式リファレンス:ObservedRealmObject - SwiftUI

@ObservedRealmObjectRealm 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>

@ObservedResultsRealmデータベースを直接参照してデータを取得するのに対して、@ObservedRealmObjectビューの引数として受け取る前提ということでしょうか?

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

私がSwift UI学習に使用した参考書

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index