Menu Docs
Página inicial do Docs
/ /
Atlas Device SDKs
/ /

Gravar dados - SwiftUI

Nesta página

  • Execute uma gravação rápida
  • Atualizar propriedades de um objeto
  • Adicionar ou remover objetos em uma coleção ObservedResults
  • Anexar um objeto a uma lista
  • Use Create para copiar um objeto no Realm
  • Realizar uma escrita explícita

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.

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 {
@ObservedRealmObject var dog: Dog
var body: some View {
VStack {
Text(dog.name)
.font(.title2)
TextField("Favorite toy", text: $dog.favoriteToy)
}
}
}

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

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.

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 {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var firstName = ""
@Persisted var lastName = ""
...
@Persisted 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 inseriu

  • Anexa o objeto Dog à lista Person do objeto 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")
}
}
}
}
}

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 {
@Persisted(primaryKey: true) var _id: UUID
@Persisted var name = ""
...
@Persisted 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)
}

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

Voltar

Passar dados de domínio entre visualizações