Execute uma gravação rápida
Além de executar gravações dentro de um bloco de transação, o Realm Swift SDK oferece um recurso de conveniência para permitir gravações rápidas sem executar explicitamente uma transação de escrita.
Ao usar os invólucros de propriedade @ObservedRealmObject ou @ObservedResults , você pode abrir implicitamente uma transação de escrita. Use o operador $ para criar uma vinculação bidirecional com o objeto de estado. Depois, ao fazer alterações no objeto vinculado ou na collection, você iniciará uma escrita implícita.
Os wrappers de propriedade do Realm SwiftUI trabalham com dados congelados para oferecer segurança de thread. Quando você usa $ para criar uma associação bidirecional, o Realm Swift SDK gerencia o descongelamento dos objetos congelados para que você possa escrever neles.
Atualizar propriedades de um objeto
Neste exemplo, criamos uma ligação bidirecional com uma das propriedades do objeto de estado. $dog.favoriteToy cria uma associação à propriedade favoriteToy do objeto modelo Dog
Quando o usuário do aplicativo atualiza esse campo neste exemplo, o Realm abre uma transação de escrita implícita e salva o novo valor no banco de dados.
struct EditDogDetails: View { var dog: Dog var body: some View { VStack { Text(dog.name) .font(.title2) TextField("Favorite toy", text: $dog.favoriteToy) } } }
Adicionar ou remover objetos em uma coleção ObservedResults
Embora uma coleção regular de resultados do Realm seja imutável, ObservedResults é uma coleção mutável que permite realizar gravações usando uma associação bidirecional. Quando você atualiza a coleção vinculada, o Realm abre uma transação de gravação implícita e salva as alterações na coleção.
Neste exemplo, removemos um elemento do conjunto de resultados usando $dogs.remove no onDelete. O uso do $dogs aqui cria uma ligação bidirecional com um BoundCollection que nos permite alterar a coleção @ObservedResults dogs.
Adicionamos um item aos resultados usando $dogs.append no addDogButton.
Estas ações escrevem diretamente na coleção @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() } } } }
Observação
O invólucro de propriedades @ObservedResults deve ser usado em uma visualização SwiftUI. Se você quiser observar os resultados em um modelo de exibição, registre um ouvinte de alterações.
Anexar um objeto a uma lista
Quando você tem uma associação bidirecional com um @ObservedRealmObject que tem uma propriedade list, você pode adicionar novos objetos à lista.
Neste exemplo, o objeto Person tem uma propriedade de lista que forma uma relação entre muitos com um ou mais cães.
class Person: Object, ObjectKeyIdentifiable { (primaryKey: true) var _id: ObjectId var firstName = "" var lastName = "" ... var dogs: List<Dog> }
Quando o usuário pressiona o botão Save, isso:
Cria um objeto
Dogcom os detalhes que o usuário inseriuAnexa o objeto
Dogà listaPersondo objetodogs
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") } } } } }
Use Create para copiar um objeto no Realm
Pode haver momentos em que você cria um novo objeto e define uma de suas propriedades para um objeto que já existe no domínio. Então, quando você for adicionar o novo objeto ao realm, verá um erro semelhante a:
Object is already managed by another Realm. Use create instead to copy it into this Realm.
Quando isso ocorrer, você pode usar o arquivo .create para inicializar o objeto e use modified: .update para definir sua propriedade para o objeto existente.
Exemplo
Considere uma versão do modelo DoggoDB Dog onde a propriedade favoriteToy não é apenas um String, mas é um objeto DogToy opcional:
class Dog: Object, ObjectKeyIdentifiable { (primaryKey: true) var _id: UUID var name = "" ... var favoriteToy: DogToy? ... }
Quando seu aplicativo for criar um novo objeto Dog, talvez ele verifique se DogToy já existe no domínio e configure a propriedade favoriteToy para o brinquedo de cachorro existente.
Quando você for anexar o novo Dog ao objeto Person, poderá ver um erro semelhante ao seguinte:
Object is already managed by another Realm. Use create instead to copy it into this Realm.
O objeto Dog permanece não gerenciado até que você o anexe à propriedade dogs do objeto Person . Quando o Realm Swift SDK verifica o objeto Dog para localizar a região que o está gerenciando atualmente, ele não encontra nada.
Quando você usa a notação $ para executar uma gravação rápida que acrescenta o objeto Dog ao objeto Person , essa gravação usa o território ao qual ele tem acesso no modo de exibição. Esta é uma instância de realm implicitamente aberta pelo wrapper de propriedade @ObservedRealmObject ou @ObservedResults . O objeto DogToy existente, no entanto, pode ser gerenciado por uma instância de domínio diferente.
Para resolver esse erro, use o método .create ao inicializar o objeto Dog e usar modified: .update para definir seu valor favoriteToy para o 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 uma escrita explícita
Em alguns casos, você pode desejar ou precisar executar explicitamente uma transação de escrita em vez de usar o $ implícito para executar uma escrita rápida. Talvez você queira fazer isso quando:
Você precisa procurar objetos adicionais para realizar uma gravação
Você precisa executar uma gravação em objetos aos quais não tem acesso no modo de exibição
Se você passar um objeto de Realm que está observando com @ObservedRealmObject ou @ObservedResults para uma função em que executa uma transação de escrita explícita que modifica o objeto, deverá descongelá-lo primeiro.
let thawedCompany = company.thaw()!
Você pode acessar o domínio que está gerenciando o objeto ou objetos ligando para .realm no objeto ou coleção:
let realm = company.realm!.thaw()
Como os wrappers de propriedade SwiftUI usam objetos congelados, você deve descongelar o território antes de poder gravar nele.
Exemplo
Considere uma versão do aplicativo DoggoDB onde um objeto Company tem uma lista de objetos Employee. Cada Employee tem uma lista de Dog objetos. Mas, por motivos comerciais, você também queria ter uma lista de objetos Dog disponíveis diretamente no objeto Company , sem estar associado a um Employee. O modelo pode se parecer com algo como:
class Company: Object, ObjectKeyIdentifiable { (primaryKey: true) var _id: ObjectId var companyName = "" var employees: List<Employee> var dogs: List<Dog> }
Considere uma visualização em que você tem acesso ao objeto Company, mas deseja realizar uma gravação explícita para adicionar um cachorro a um funcionário existente. Sua função pode se parecer com algo como:
// 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) } }