Gravar dados - SwiftUI
Nesta página
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 { true) var _id: ObjectId (primaryKey: var firstName = "" var lastName = "" ... var dogs: List<Dog> }
Quando o usuário pressiona o botão Save
, isso:
Cria um objeto
Dog
com os detalhes que o usuário inseriuAnexa o objeto
Dog
à listaPerson
do 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 { true) var _id: UUID (primaryKey: 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 { true) var _id: ObjectId (primaryKey: 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) } }