データの書き込み - SwiftUI
項目一覧
クイック書き込みの実行
トランザクション ブロック内で書込みを実行するだけでなく、Realm Swift SDK は、書込みトランザクションを明示的に実行せずに迅速な書込みを可能にする便利な機能を提供します。
@ObservedRealmObject
または@ObservedResults
プロパティ ラッパーを使用すると、書込みトランザクションを暗黙的に開くことができます。 $
演算子を使用して、状態オブジェクトへの 2 方向バインディングを作成します。 次に、バインドされたオブジェクトまたはコレクションに変更を加えると、暗黙的な書込み (write) が開始されます。
Realm SwiftUI プロパティ ラッパーは、スレッドの安全性を確保するために固定されたデータを操作します。 $
を使用して 2 方向バインディングを作成すると、Realm Swift SDK が固定されたオブジェクトの解凍を管理するため、ユーザーはそれらに書込み (write) が可能になります。
オブジェクトのプロパティの更新
この例では、状態オブジェクトの プロパティの 1 つを使用した 2 方向バインディングを作成します。 $dog.favoriteToy
はモデル ドキュメント オブジェクトのfavoriteToy
プロパティへのバインディングを作成します
この例のアプリ ユーザーがそのフィールドを更新すると、Realm は暗黙的な書込みトランザクション (write transaction) を開き、新しい値をデータベースに保存します。
struct EditDogDetails: View { var dog: Dog var body: some View { VStack { Text(dog.name) .font(.title2) TextField("Favorite toy", text: $dog.favoriteToy) } } }
ObservedResults コレクション内のオブジェクトの追加または削除
通常のRealm 結果コレクションは不変ですが、 ObservedResultsは、2 方向バインディングを使用して書込みを実行できる可変コレクションです。 バインドされたコレクションを更新すると、Realm は暗黙的な書込みトランザクション (write transaction) を開き、コレクションへの変更を保存します。
この例では、 onDelete
の$dogs.remove
を使用して結果セットから要素を削除します。 ここで$dogs
を使用すると、 BoundCollection
への 2 方向バインディングが作成され、 @ObservedResults
dogs
コレクションをミューテーションできます。
addDogButton
で$dogs.append
を使用して結果にアイテムを追加します。
これらのアクションは@ObservedResults
コレクションに直接書込みます。
struct DogsListView: View { Dog.self) var dogs ( var body: some View { NavigationView { VStack { // The list shows the dogs in the realm. List { ForEach(dogs) { dog in DogRow(dog: dog) // Because `$dogs` here accesses an ObservedResults // collection, we can remove the specific dog from the collection. // Regular Realm Results are immutable, but you can write directly // to an `@ObservedResults` collection. }.onDelete(perform: $dogs.remove) }.listStyle(GroupedListStyle()) .navigationBarTitle("Dogs", displayMode: .large) .navigationBarBackButtonHidden(true) // Action bar at bottom contains Add button. HStack { Spacer() Button(action: { // The bound collection automatically // handles write transactions, so we can // append directly to it. This example assumes // we have some values to populate the Dog object. $dogs.append(Dog(value: ["name":"Bandido"])) }) { Image(systemName: "plus") } .accessibilityIdentifier("addDogButton") }.padding() } } } }
注意
@ObservedResults
プロパティ ラッパーは SwiftUI ビューで使用するためのものです。 ビューモデルで結果を観察するには、変更リスナーを登録します。
リストへのオブジェクトの追加
リスト プロパティを持つ@ObservedRealmObject
との双方向バインディングがある場合は、新しいオブジェクトをリストに追加できます。
この例では、 Person
オブジェクトには、1 台以上の犬との対多関係を形成する リスト プロパティがあります。
class Person: Object, ObjectKeyIdentifiable { true) var _id: ObjectId (primaryKey: var firstName = "" var lastName = "" ... var dogs: List<Dog> }
ユーザーがSave
ボタンを押すと、次のような状況が生じます。
ユーザーが入力した詳細を含む
Dog
オブジェクトを作成しますDog
オブジェクトをPerson
オブジェクトのdogs
リストに追加する
struct AddDogToPersonView: View { var person: Person var isInAddDogView: Bool var name = "" var breed = "" var weight = 0 var favoriteToy = "" var profileImageUrl: URL? var body: some View { Form { TextField("Dog's name", text: $name) TextField("Dog's breed", text: $breed) TextField("Dog's weight", value: $weight, format: .number) TextField("Dog's favorite toy", text: $favoriteToy) TextField("Image link", value: $profileImageUrl, format: .url) .keyboardType(.URL) .textInputAutocapitalization(.never) .disableAutocorrection(true) Section { Button(action: { let dog = createDog(name: name, breed: breed, weight: weight, favoriteToy: favoriteToy, profileImageUrl: profileImageUrl) $person.dogs.append(dog) isInAddDogView.toggle() }) { Text("Save") } Button(action: { isInAddDogView.toggle() }) { Text("Cancel") } } } } }
「作成」を使用してオブジェクトを Realm にコピーする
新しいオブジェクトを作成し、そのプロパティの 1 つを Realm にすでに存在するオブジェクトに設定する場合がある場合があります。 次に、 Goを実行して新しいオブジェクトを Realm に追加すると、次のようなエラーが表示されます。
Object is already managed by another Realm. Use create instead to copy it into this Realm.
このような場合は、 .createを使用できます メソッドを使用してオブジェクトを初期化し、 modified: .update
を使用してそのプロパティを既存のオブジェクトに設定します。
例
favoriteToy
プロパティがString
だけでなく、任意のDogToy
オブジェクトである DogoDB Dog
モデルのバージョンを検討します。
class Dog: Object, ObjectKeyIdentifiable { true) var _id: UUID (primaryKey: var name = "" ... var favoriteToy: DogToy? ... }
アプリで新しいDog
オブジェクトを作成するときは、 DogToy
が Realm にすでに存在するかどうかが確認され、次にfavoriteToy
プロパティが既存の犬の状態に設定されます。
新しい Dog
を Person
オブジェクトに追加しようとすると、次のようなエラーが表示される場合がありGo 。
Object is already managed by another Realm. Use create instead to copy it into this Realm.
Dog
オブジェクトは、 Person
オブジェクトのdogs
プロパティに追加するまで管理されません。 Realm Swift SDK がDog
オブジェクトをチェックして、現在管理している Realm を見つけても、何も見つかりません。
$
表記を使用して、 Dog
オブジェクトをPerson
オブジェクトに追加するクイック 書込みを実行すると、この書込みは ビュー内のアクセス権を持つ Realm を使用します。 これは、 @ObservedRealmObject
または@ObservedResults
プロパティ ラッパーによって暗黙的に開かれる Realm インスタンスです。 ただし、既存のDogToy
オブジェクトは別の Realm インスタンスによって管理される場合があります。
このエラーを解決するには、 .create メソッドを使用してDog
オブジェクトを初期化し、 modified: .update
を使用してそのfavoriteToy
値を既存のオブジェクトに設定する場合は次のとおりです。
// When working with an `@ObservedRealmObject` `Person`, this is a frozen object. // Thaw the object and get its realm to perform the write to append the new dog. let thawedPersonRealm = frozenPerson.thaw()!.realm! try! thawedPersonRealm.write { // Use the .create method with `update: .modified` to copy the // existing object into the realm let dog = thawedPersonRealm.create(Dog.self, value: ["name": "Maui", "favoriteToy": wubba], update: .modified) person.dogs.append(dog) }
明示的な書込み (write) の実行
場合によっては、暗黙的な$
を使用してクイック書き込みを実行する代わりに、書込みトランザクションを明示的に実行する必要がある場合や が必要になる場合があります。 次の場合には、これを実行することをお勧めします。
書き込みを実行するには追加のオブジェクトを検索する必要があります
ビューでアクセス権のないオブジェクトへの書込みを実行する必要があります
@ObservedRealmObject
または@ObservedResults
で監視しているオブジェクトを関数に渡す場合は、オブジェクトを変更する明示的な書込みトランザクションを実行する場合は、最初にそれを解凍する必要があります。
let thawedCompany = company.thaw()!
オブジェクトまたはコレクションで.realm
を呼び出すことで、 オブジェクトを管理している Realm にアクセスできます。
let realm = company.realm!.thaw()
SwiftUI プロパティ ラッパーは固定されたオブジェクトを使用するため、Realm に書き込む前に Realm を解凍する必要があります。
例
Company
オブジェクトがEmployee
オブジェクトのリストを持つ DogoDB アプリのバージョンを検討してみましょう。 各Employee
にはDog
オブジェクトのリストがあります。 しかし、ビジネス上の理由で、 Employee
に関連付けられることなく、 Company
オブジェクトで直接使用できるDog
オブジェクトのリストも必要でした。 モデルは次のようになります。
class Company: Object, ObjectKeyIdentifiable { true) var _id: ObjectId (primaryKey: var companyName = "" var employees: List<Employee> var dogs: List<Dog> }
Company
オブジェクトにアクセスできても、明示的な書込みを実行して既存の従業員に既存の犬を追加したいビューを検討してください。 関数は、次のようになります。
// The `frozenCompany` here represents an `@ObservedRealmObject var company: Company` performAnExplicitWrite(company: frozenCompany, employeeName: "Dachary", dogName: "Maui") func performAnExplicitWrite(company: Company, employeeName: String, dogName: String) { // Get the realm that is managing the `Company` object you passed in. // Thaw the realm so you can write to it. let realm = company.realm!.thaw() // Thawing the `Company` object that you passed in also thaws the objects in its List properties. // This lets you append the `Dog` to the `Employee` without individually thawing both of them. let thawedCompany = company.thaw()! let thisEmployee = thawedCompany.employees.where { $0.name == employeeName }.first! let thisDog = thawedCompany.dogs.where { $0.name == dogName }.first! try! realm.write { thisEmployee.dogs.append(thisDog) } }