Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

データの書き込み - SwiftUI

項目一覧

  • クイック書き込みの実行
  • オブジェクトのプロパティの更新
  • ObservedResults コレクション内のオブジェクトの追加または削除
  • リストへのオブジェクトの追加
  • 「作成」を使用してオブジェクトを Realm にコピーする
  • 明示的な書込み (write) の実行

トランザクション ブロック内で書込みを実行するだけでなく、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 {
@ObservedRealmObject var dog: Dog
var body: some View {
VStack {
Text(dog.name)
.font(.title2)
TextField("Favorite toy", text: $dog.favoriteToy)
}
}
}

通常のRealm 結果コレクションは不変ですが、 ObservedResultsは、2 方向バインディングを使用して書込みを実行できる可変コレクションです。 バインドされたコレクションを更新すると、Realm は暗黙的な書込みトランザクション (write transaction) を開き、コレクションへの変更を保存します。

この例では、 onDelete$dogs.removeを使用して結果セットから要素を削除します。 ここで$dogsを使用すると、 BoundCollectionへの 2 方向バインディングが作成され、 @ObservedResults dogsコレクションをミューテーションできます。

addDogButton$dogs.appendを使用して結果にアイテムを追加します。

これらのアクションは@ObservedResultsコレクションに直接書込みます。

struct DogsListView: View {
@ObservedResults(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 {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var firstName = ""
@Persisted var lastName = ""
...
@Persisted var dogs: List<Dog>
}

ユーザーがSaveボタンを押すと、次のような状況が生じます。

  • ユーザーが入力した詳細を含むDogオブジェクトを作成します

  • DogオブジェクトをPersonオブジェクトのdogsリストに追加する

struct AddDogToPersonView: View {
@ObservedRealmObject var person: Person
@Binding var isInAddDogView: Bool
@State var name = ""
@State var breed = ""
@State var weight = 0
@State var favoriteToy = ""
@State 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")
}
}
}
}
}

新しいオブジェクトを作成し、そのプロパティの 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 {
@Persisted(primaryKey: true) var _id: UUID
@Persisted var name = ""
...
@Persisted var favoriteToy: DogToy?
...
}

アプリで新しいDogオブジェクトを作成するときは、 DogToyが Realm にすでに存在するかどうかが確認され、次にfavoriteToyプロパティが既存の犬の状態に設定されます。

新しい DogPerson オブジェクトに追加しようとすると、次のようなエラーが表示される場合があり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)
}

場合によっては、暗黙的な$を使用してクイック書き込みを実行する代わりに、書込みトランザクションを明示的に実行する必要がある場合や が必要になる場合があります。 次の場合には、これを実行することをお勧めします。

  • 書き込みを実行するには追加のオブジェクトを検索する必要があります

  • ビューでアクセス権のないオブジェクトへの書込みを実行する必要があります

@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 {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var companyName = ""
@Persisted var employees: List<Employee>
@Persisted 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)
}
}

戻る

データビュー間で Realm を渡す