Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
SwiftUI

Escribir datos - SwiftUI

Además de realizar escrituras dentro de un bloque de transacción, el SDK Realm Swift ofrece una función conveniente para permitir escrituras rápidas sin realizar explícitamente una transacción de escritura.

Cuando utilices el @ObservedRealmObject o los contenedores de propiedades @ObservedResults, puede abrir implícitamente una transacción de escritura. Use el operador $ para crear un enlace bidireccional al objeto de estado. Luego, al realizar cambios en el objeto o colección enlazados, se inicia una escritura implícita.

The Realm SwiftUI property wrappers work with frozen data to provide thread safety. When you use $ to create a two-way binding, the Realm Swift SDK manages thawing the frozen objects so you can write to them.

In this example, we create a two-way binding with one of the state object's properties. $dog.favoriteToy creates a binding to the model Dog object's favoriteToy property

When the app user updates that field in this example, Realm opens an implicit write transaction and saves the new value to the database.

struct EditDogDetails: View {
@ObservedRealmObject var dog: Dog
var body: some View {
VStack {
Text(dog.name)
.font(.title2)
TextField("Favorite toy", text: $dog.favoriteToy)
}
}
}

Si bien una colección regular de Resultados de Reino es inmutable, ObservedResults es una colección mutable que permite realizar escrituras mediante un enlace bidireccional. Al actualizar la colección enlazada, Realm abre una transacción de escritura implícita y guarda los cambios en la colección.

In this example, we remove an element from the results set using $dogs.remove in the onDelete. Using the $dogs here creates a two-way binding to a BoundCollection that lets us mutate the @ObservedResults dogs collection.

Se añade un elemento a los resultados usando $dogs.append en el addDogButton.

These actions write directly to the @ObservedResults collection.

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()
}
}
}
}

Nota

The @ObservedResults property wrapper is intended for use in a SwiftUI View. If you want to observe results in a view model, register a change listener.

Cuando tienes un enlace bidireccional con un @ObservedRealmObject que tiene una propiedad de lista, puedes agregar objetos nuevos a la lista.

En este ejemplo, el Person objeto tiene una propiedad de lista que forma una relación de muchos con uno o más perros.

class Person: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var firstName = ""
@Persisted var lastName = ""
...
@Persisted var dogs: List<Dog>
}

When the user presses the Save button, this:

  • Creates a Dog object with the details that the user has entered

  • Appends the Dog object to the Person object's dogs list

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")
}
}
}
}
}

There may be times when you create a new object, and set one of its properties to an object that already exists in the realm. Then, when you go to add the new object to the realm, you see an error similar to:

Object is already managed by another Realm. Use create instead to copy it into this Realm.

When this occurs, you can use the .create method to initialize the object, and use modified: .update to set its property to the existing object.

Ejemplo

Consider a version of the DoggoDB Dog model where the favoriteToy property isn't just a String, but is an optional DogToy object:

class Dog: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: UUID
@Persisted var name = ""
...
@Persisted var favoriteToy: DogToy?
...
}

Cuando tu aplicación vaya a crear un nuevo objeto Dog, tal vez compruebe si el DogToy ya existe en el realm y, a continuación, establezca la propiedad favoriteToy en el juguete para perro existente.

When you go to append the new Dog to the Person object, you may see an error similar to:

Object is already managed by another Realm. Use create instead to copy it into this Realm.

El objeto Dog permanece no gestionado hasta que lo añadas a la propiedad dogs del objeto Person. Cuando el SDK de Realm Swift verifica el objeto Dog para encontrar el realm que actualmente lo gestiona, no encuentra nada.

When you use the $ notation to perform a quick write that appends the Dog object to the Person object, this write uses the realm it has access to in the view. This is a realm instance implicitly opened by the @ObservedRealmObject or @ObservedResults property wrapper. The existing DogToy object, however, may be managed by a different realm instance.

To solve this error, use the .create method when you initialize the Dog object, and use modified: .update to set its favoriteToy value to the existing object:

// 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)
}

En algunos casos, es posible que desee o necesite realizar explícitamente una transacción de escritura en lugar de usar el $ implícito para realizar una guardar rápida. Es posible que desee hacer esto cuando:

  • You need to look up additional objects to perform a write

  • You need to perform a write to objects you don't have access to in the view

Si pasa un objeto que está observando con @ObservedRealmObject o @ObservedResults a una función en la que realiza una transacción de escritura explícita que modifica el objeto, primero debe descongelarlo.

let thawedCompany = company.thaw()!

You can access the realm that is managing the object or objects by calling .realm on the object or collection:

let realm = company.realm!.thaw()

Debido a que los contenedores de propiedades de SwiftUI utilizan objetos congelados, debes descongelar el reino antes de poder escribir en él.

Ejemplo

Consider a version of the DoggoDB app where a Company object has a list of Employee objects. Each Employee has a list of Dog objects. But for business reasons, you also wanted to have a list of Dog objects available directly on the Company object, without being associated with an Employee. The model might look something like:

class Company: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var companyName = ""
@Persisted var employees: List<Employee>
@Persisted var dogs: List<Dog>
}

Considere una vista con acceso al objeto Company, pero desea realizar una escritura explícita para agregar un perro existente a un empleado existente. Su función podría ser similar a la siguiente:

// 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)
}
}

Volver

Pass Realm Data Between Views

En esta página