Realizar una escritura rápida
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.
Los contenedores de propiedades de Realm SwiftUI funcionan con datos congelados para proporcionar seguridad en subprocesos. Al usar $ para crear un enlace bidireccional, el SDK de Realm Swift gestiona la recuperación de los objetos congelados para que se pueda escribir en ellos.
Actualizar las propiedades de un objeto
En este ejemplo, creamos un enlace bidireccional con una de las propiedades del objeto de estado. $dog.favoriteToy crea un enlace a la propiedad favoriteToy del objeto de modelo Perro
Cuando el usuario de la aplicación actualiza ese campo en este ejemplo, Realm abre una transacción de escritura implícita y guarda el nuevo valor en la base de datos.
struct EditDogDetails: View { var dog: Dog var body: some View { VStack { Text(dog.name) .font(.title2) TextField("Favorite toy", text: $dog.favoriteToy) } } }
Agregar o eliminar objetos en una colección de resultados observados
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.
En este ejemplo, eliminamos un elemento del conjunto de resultados usando $dogs.remove en onDelete. Al usar $dogs, se crea un enlace bidireccional a BoundCollection que permite mutar la colección @ObservedResults dogs.
Añadimos un elemento a los resultados utilizando $dogs.append en addDogButton.
Estas acciones escriben directamente en la colección @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() } } } }
Nota
El @ObservedResults contenedor de propiedad está diseñado para usarse en una vista de SwiftUI. Si desea observar los resultados en un modelo de vista, registre un detector de cambios.
Añadir un objeto a una lista
Cuando tiene un enlace bidireccional con un @ObservedRealmObject que tiene una propiedad de lista, puede agregar nuevos objetos 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 { (primaryKey: true) var _id: ObjectId var firstName = "" var lastName = "" ... var dogs: List<Dog> }
Cuando el usuario presiona el botón Save, esto:
Crea un objeto
Dogcon los detalles que el usuario ha ingresadoAñade el objeto
Doga la listadogsdel objetoPerson
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") } } } } }
Utilice Crear para copiar un objeto en el reino
Puede haber ocasiones en las que, al crear un nuevo objeto y asignar una de sus propiedades a un objeto ya existente en el dominio, se produzca un error similar al siguiente al agregar el nuevo objeto al dominio.
Object is already managed by another Realm. Use create instead to copy it into this Realm.
Cuando esto ocurre, puede utilizar el método .create para inicializar el objeto y utilizar modified: .update para establecer su propiedad en el objeto existente.
Ejemplo
Considere una versión del modelo DoggoDB Dog donde la propiedad favoriteToy no es solo un String, sino que es un objeto DogToy opcional:
class Dog: Object, ObjectKeyIdentifiable { (primaryKey: true) var _id: UUID var name = "" ... var favoriteToy: DogToy? ... }
Cuando su aplicación intenta crear un nuevo objeto Dog, tal vez verifique si el DogToy ya existe en el reino y luego establezca la propiedad favoriteToy en el juguete para perro existente.
Cuando intentas agregar el nuevo Dog al objeto Person, es posible que veas un error similar al siguiente:
Object is already managed by another Realm. Use create instead to copy it into this Realm.
El objeto Dog permanece sin administrar hasta que lo agregue a la propiedad dogs del objeto Person. Cuando el SDK de Swift de Realm busca el objeto Dog para encontrar el dominio que lo administra, no encuentra nada.
Al usar la notación $ para realizar una escritura rápida que añade el objeto Dog al objeto Person, esta escritura utiliza el dominio al que tiene acceso en la vista. Esta instancia de dominio se abre implícitamente mediante el contenedor de propiedades @ObservedRealmObject o @ObservedResults. Sin embargo, el objeto DogToy existente puede ser administrado por una instancia de dominio diferente.
Para resolver este error, utilice el método .create cuando inicialice el Dog objeto y utilice modified: .update para establecer su favoriteToy valor en el objeto existente:
// 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) }
Realizar una escritura explícita
En algunos casos, puede que desee o necesite realizar una transacción de escritura explícita en lugar de usar el $ implícito para realizar una escritura rápida. Puede que le convenga hacer esto cuando:
Necesitas buscar objetos adicionales para realizar una escritura
Necesita realizar una escritura en objetos a los que no tiene acceso en la vista
Si pasa un objeto que está observando con @ObservedRealmObject o @ObservedResults a una función donde realiza una transacción de escritura explícita que modifica el objeto, primero debe descongelarlo.
let thawedCompany = company.thaw()!
Puede acceder al reino que administra el objeto o los objetos llamando a .realm en el objeto o la colección:
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
Considere una versión de la aplicación DoggoDB donde un objeto Company tiene una lista de Employee objetos. Cada Employee tiene una lista de Dog objetos. Sin embargo, por razones de negocio, también desea tener una lista de Dog objetos disponibles directamente en el objeto Company, sin estar asociada a un Employee. El modelo podría ser similar a:
class Company: Object, ObjectKeyIdentifiable { (primaryKey: true) var _id: ObjectId var companyName = "" var employees: List<Employee> 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) } }