Menu Docs

Página inicial do DocsDesenvolver aplicaçõesAtlas Device SDKs

Use o Realm com prévias do SwiftUI

Nesta página

  • Visão geral
  • Inicializar um objeto para uma visualização detalhada
  • Use condicionalmente ObservedResults em uma exibição de lista
  • Crie um domínio com dados para visualizações
  • Use um domínio na memória
  • Excluir visualizações da SwiftUI
  • Obtenha informações detalhadas sobre falhas na visualização da SwiftUI
  • Use um domínio sincronizado em visualizações

As visualizações da SwiftUI são uma ferramenta útil durante o desenvolvimento. Você pode trabalhar com os dados do Realm nas visualizações da SwiftUI de algumas maneiras:

  • Inicialize objetos individuais para usar em visualizações detalhadas

  • Use condicionalmente uma array de objetos no lugar de @ObservedResults

  • Criar um domínio que contenha dados para as pré-visualizações

A depuração da visualização do SwiftUI pode ser opaca, portanto, também temos algumas dicas para depurar problemas com Realms persistentes nas visualizações do SwiftUI.

No caso mais simples, você pode usar o SwiftUI Previews com um ou mais objetos que usam propriedades Realm que você pode definir diretamente na inicialização. Talvez você queira fazer isso ao visualizar uma visualização detalhada. Considere o DogDetailView do DoggoDB:

struct DogDetailView: View {
@ObservedRealmObject var dog: Dog
var body: some View {
VStack {
Text(dog.name)
.font(.title2)
Text("\(dog.name) is a \(dog.breed)")
AsyncImage(url: dog.profileImageUrl) { image in
image.resizable()
} placeholder: {
ProgressView()
}
.aspectRatio(contentMode: .fit)
.frame(width: 150, height: 150)
Text("Favorite toy: \(dog.favoriteToy)")
}
}
}

Crie uma extensão para seu objeto de modelo. Onde você coloca essa extensão depende da convenção em sua base de código. Você pode colocá-lo diretamente no arquivo de modelo, ter um diretório dedicado para dados de exemplo ou usar alguma outra convenção em sua base de código.

Nesta extensão, inicialize um ou mais objetos do Realm com static let:

extension Dog {
static let dog1 = Dog(value: ["name": "Lita", "breed": "Lab mix", "weight": 27, "favoriteToy": "Squeaky duck", "profileImageUrl": "https://www.corporaterunaways.com/images/2021/04/lita-768x768.jpeg"])
static let dog2 = Dog(value: ["name": "Maui", "breed": "English Springer Spaniel", "weight": 42, "favoriteToy": "Wubba", "profileImageUrl": "https://www.corporaterunaways.com/images/2021/04/maui_with_leaf-768x576.jpeg"])
static let dog3 = Dog(value: ["name": "Ben", "breed": "Border Collie mix", "weight": 48, "favoriteToy": "Frisbee", "profileImageUrl": "https://www.corporaterunaways.com/images/2012/03/ben-630x420.jpg"])
}

Neste exemplo, inicializamos objetos com um valor. Você só pode inicializar objetos com um valor quando seu modelo contiver propriedades que você possa inicializar diretamente. Se o objeto de modelo contiver propriedades que só podem ser mutáveis em uma transação de gravação, como uma propriedade List, você deverá criar um território para usar com suas visualizações SwiftUI.

Depois de inicializar um objeto como uma extensão de sua classe de modelo, você poderá usá-lo em sua visualização SwiftUI. Você pode passar o objeto diretamente para a Visualização na Visualização:

struct DogDetailView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
DogDetailView(dog: Dog.dog1)
}
}
}

Quando você usa @ObservedResults em uma exibição de lista, isso abre implicitamente um realm e a query. Para que isso funcione em uma visualização, você precisa de um domínio preenchido com dados. Como uma alternativa, você pode utilizar condicionalmente uma array estática em Visualizações prévias e utilizar somente a variável @ObservedResults ao executar o aplicativo.

Você poderia fazer isso de várias maneiras, mas, para facilitar a leitura e a compreensão do nosso código, criaremos um EnvironmentValue que pode detectar se o aplicativo está sendo executado em uma visualização:

import Foundation
import SwiftUI
public extension EnvironmentValues {
var isPreview: Bool {
#if DEBUG
return ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
#else
return false
#endif
}
}

Em seguida, podemos usar isso como um valor de ambiente em nossa visualização e alterar condicionalmente a variável que usamos com base no fato de estarmos ou não em uma visualização.

Este exemplo baseia-se na extensão do cão que definimos acima. Criaremos um dogArray como um static let em nossa extensão Dog e incluiremos os objetos item que já criamos:

static let dogArray = [dog1, dog2, dog3]

Em seguida, quando iterarmos pela nossa Lista, use o dogArray estático se estiver em execução em uma Visualização ou use a query @ObservedResults se não estiver em uma Visualização.

struct DogsView: View {
@Environment(\.isPreview) var isPreview
@ObservedResults(Dog.self) var dogs
var previewDogs = Dog.dogArray
var body: some View {
NavigationView {
VStack {
List {
if isPreview {
ForEach(previewDogs) { dog in
DogRow(dog: dog)
}
} else {
ForEach(dogs) { dog in
DogRow(dog: dog)
}.onDelete(perform: $dogs.remove)
}
}
... More View code

Isso tem a vantagem de ser leve e não persistir nenhum dado, mas a desvantagem de tornar o código de visualização mais detalhado. Se preferir um código de visualização mais limpo, você pode criar um domínio com os dados que você usa nas visualizações prévias.

Em alguns casos, sua única opção para ver os dados do domínio em uma visualização do SwiftUI é criar um domínio que contenha os dados. Você pode fazer isso ao preencher uma propriedade que só pode ser preenchida durante uma transação de gravação, em vez de ser inicializada diretamente com um valor, como uma List ou MutableSet. Talvez você também queira fazer isso se a sua visualização depender de hierarquias de objetos mais complexas que são passadas de outras visualizações.

No entanto, usar um domínio diretamente injeta estado em suas visualizações do SwiftUI, o que pode trazer desvantagens. Esteja você usando Realm ou Core Data, as visualizações do SwiftUI com estado podem causar problemas como:

  • Ver dados inesperados ou duplicados devido à reexecução repetida das etapas de criação do arquivo de domínio repetidamente

  • Necessidade de realizar uma migração dentro do SwiftUI Preview ao fazer alterações no modelo

  • Possíveis problemas relacionados à mudança de estado nas visualizações

  • Falhas inexplicáveis ou problemas de desempenho relacionados a problemas que não são exibidos de forma visível nas visualizações da SwiftUI

Você pode evitar ou corrigir alguns destes problemas com estas dicas:

Você pode criar uma variável estática para seu domínio na extensão do modelo. É aqui que você faz o trabalho para preencher seu domínio. Em nosso caso, criamos um Person e anexamos alguns objetos Dog à propriedade Lista dogs . Este exemplo se baseia no exemplo acima, em que inicializamos alguns objetos Dog em uma extensão Dog.

Criaremos uma extensão Person e criaremos um único objeto Person nessa extensão. Em seguida, criaremos um previewRealm adicionando o Person que acabamos de criar e anexando o exemplo Dog objetos da extensão Dog.

Para evitar adicionar esses objetos mais de uma vez, adicionamos uma verificação para ver se a Pessoa já existe executar uma query de objetos de Pessoa e verificando se a contagem é 1. Se o território contiver uma Pessoa, podemos usá-la em nossa Visualização do SwiftUI. Caso contrário, adicionamos os dados.

static var previewRealm: Realm {
var realm: Realm
let identifier = "previewRealm"
let config = Realm.Configuration(inMemoryIdentifier: identifier)
do {
realm = try Realm(configuration: config)
// Check to see whether the in-memory realm already contains a Person.
// If it does, we'll just return the existing realm.
// If it doesn't, we'll add a Person append the Dogs.
let realmObjects = realm.objects(Person.self)
if realmObjects.count == 1 {
return realm
} else {
try realm.write {
realm.add(person)
person.dogs.append(objectsIn: [Dog.dog1, Dog.dog2, Dog.dog3])
}
return realm
}
} catch let error {
fatalError("Can't bootstrap item data: \(error.localizedDescription)")
}
}

Para usá-lo na pré-visualização da interface do usuário do SwiftUI, nosso código ProfileView espera um perfil. Esta é uma projeção do objeto Pessoa. Em nossa visualização prévia, podemos obter o domínio, consultá-lo pelo Perfil e passá-lo para a visualização:

struct ProfileView_Previews: PreviewProvider {
static var previews: some View {
let realm = Person.previewRealm
let profile = realm.objects(Profile.self)
ProfileView(profile: profile.first!)
}
}

Se você não tiver um View que esteja esperando que um objeto de realm seja transmitido, mas em vez disso usar @ObservedResults para executar uma query de um realm ou trabalhar com um realm existente, você pode injetar o realm no modo de exibição como um valor de ambiente:

struct SomeListView_Previews: PreviewProvider {
static var previews: some View {
SomeListView()
.environment(\.realm, Person.previewRealm)
}
}

Quando possível, use um domínio na memória para contornar alguns dos problemas relacionados ao estado que podem resultar do uso de um banco de dados em uma visualização do SwiftUI.

Use a propriedade de configuração inMemoryIdentifier ao inicializar o realm.

static var previewRealm: Realm {
var realm: Realm
let identifier = "previewRealm"
let config = Realm.Configuration(inMemoryIdentifier: identifier)
do {
realm = try Realm(configuration: config)
// ... Add data to realm

Observação

Não use a propriedade de configuração deleteRealmIfMigrationNeeded ao inicializar um realm para SwiftUI Previews. Devido à forma como a Apple implementou o SwiftUI Previews, o uso dessa propriedade para contornar os problemas de migração faz com que o SwiftUI Previews falhe.

Se você tiver outros problemas de visualização do SwiftUI relacionados ao estado, como uma falha ao carregar um realm em uma visualização devido à necessidade de migração, há algumas coisas que você pode fazer para remover os dados de visualização armazenados em cache.

A correção recomendada pela Apple é fechar o Xcode e usar a linha de comando para excluir todos os seus dados existentes do SwiftUI Preview.

  1. Feche o Xcode.

  2. Na linha de comando, execute:

    xcrun simctl --set previews delete all

É possível que os dados persistam após executar este comando. Isso provavelmente se deve ao fato de o Xcode reter uma referência devido a algo na visualização e não conseguir excluí-la. Você também pode tentar estas etapas para resolver problemas:

  • Construir para um simulador diferente

  • Reinicie o computador e execute novamente xcrun simctl --set previews delete all

  • Exclua os dados de visualização armazenados diretamente. Esses dados são armazenados em ~/Library/Developer/Xcode/UserData/Previews.

Se você tiver um travamento inexplicável na visualização da SwiftUI ao usar o domínio, primeiro tente executar o aplicativo no simulador. As mensagens de erro e os logs disponíveis para o simulador facilitam a localização e o diagnóstico de problemas. Se você pode depurar o problema no simulador, esta é a rota mais fácil.

Se não for possível replicar uma falha do SwiftUI Preview no simulador, você poderá visualizar os registros de falhas do aplicativo SwiftUI Preview. Estes logs estão disponíveis em ~/Library/Logs/DiagnosticReports/. Às vezes, esses registros aparecem após um atraso, então aguarde alguns minutos após uma falha se você não ver o registro relevante imediatamente.

Se o seu aplicativo utiliza Atlas Device Sync, você pode se perguntar como utilizar um domínio sincronizado em suas visualizações da SwiftUI. Uma prática melhor é usar objetos estáticos ou um território local que você preenche com dados para suas visualizações do SwiftUI.

Em nosso aplicativo de exemplo, podemos visualizar uma exibição associada ao Device Sync - o LoginView - sem precisar usar um realm:

struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView()
}
}

Como estamos visualizando apenas a interface do usuário estática, não precisamos nos preocupar com o SyncContentView que contém a lógica de mostrar o LoginView ou ir para o OpenSyncedRealmView. Também podemos ignorar a visualização do OpenSyncedRealmView, porque isso apenas lida com a lógica associada à abertura de um realm sincronizado e preenchê-lo para o DogsView. Portanto, a próxima visualização que queremos ver em um Preview é DogsView.

Felizmente, com o Realm, o código para trabalhar com o domínio não se importa se o domínio usa o Device Sync ou não - você trabalha com o domínio da mesma maneira. Assim, podemos usar o mesmo território local que criamos no exemplo acima na visualização do SwiftUI.

struct DogsView_Previews: PreviewProvider {
static var previews: some View {
let realm = Person.previewRealm
DogsView()
.environment(\.realm, realm)
}
}
← Sincronize dados em segundo plano com o SwiftUI - Swift SDK