Agrupar um arquivo Realm - Swift SDK
Nesta página
Observação
Agrupar domínios sincronizados
Swift SDK versão 10.23.0 introduziu a capacidade de agrupar domínios sincronizados. Antes da versão 10.23.0, só era possível agrupar domínios locais.
O Realm suporta o agrupamento de arquivos realm. Ao agrupar um arquivo de domínio, você inclui um banco de dados e todos os seus dados no download do aplicativo.
Isso permite que os usuários iniciem aplicativos pela primeira vez com um conjunto de dados iniciais. Para domínios sincronizados, o agrupamento pode evitar um download inicial demorado na primeira vez que um usuário abre seu aplicação. Em vez disso, os usuários só precisam baixar as alterações sincronizadas que ocorreram desde que você gerou o arquivo agrupado.
Importante
Agrupar domínios sincronizados
Se o seu aplicação de backend usar Flexible Sync, os usuários poderão enfrentar um reinício do cliente na primeira vez que abrirem o arquivo de Realm agrupado. Isso pode ocorrer quando o tempo máximo offline do cliente está habilitado (o tempo máximo offline do cliente está habilitado por padrão). Se o arquivo de Realm agrupado tiver sido gerado mais do que o número de dias especificado pela configuração de tempo máximo offline do cliente antes de o usuário sincronizar pela primeira vez, o usuário experimenta uma reinício do cliente.
Os aplicativos que executam uma redefinição do cliente baixam o estado completo do domínio do backend do aplicativo. Isso nega as vantagens de agrupar um arquivo de domínio. Para evitar o reinício do cliente e preservar as vantagens do agrupamento de arquivos realm:
Evite usar o tempo offline máximo do cliente em aplicativos que agrupam um domínio sincronizado.
Se o seu aplicativo usar o tempo máximo offline do cliente, certifique-se de que o download do aplicativo sempre inclua um arquivo de domínio sincronizado recentemente. Gere um novo arquivo a cada versão do aplicativo e garanta que nenhuma versão permaneça atual por mais do que o número máximo de dias de tempo offline do cliente .
Visão geral
Para criar e agrupar um arquivo de domínio com seu aplicativo:
Crie um arquivo de domínio que contenha os dados que você deseja agrupar.
Agrupe o arquivo realm em seu aplicativo de produção.
Em seu aplicativo de produção, abra o domínio a partir do arquivo de ativos agrupados. Para domínios sincronizados, você deve fornecer a chave de partição.
Criar um arquivo Realm para agrupamento
Construa um aplicativo de domínio temporário que compartilhe o modelo de dados do seu aplicativo.
Abra um domínio e adicione os dados que deseja agrupar. Se estiver usando um domínio sincronizado, dê tempo para que o domínio sincronize totalmente.
Use o método writeCopy(configuration:) para copiar o domínio para um novo arquivo:
Dica
Se a sua aplicação acessar Realm em um contexto do async/await
, marque o código com @MainActor
para evitar falhas relacionadas a threading.
try await createBundledRealm() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func createBundledRealm() async throws { let app = App(id: YOUR_APP_SERVICES_APP_ID) // Log in the user whose realm you want to copy for bundling let seedUser = try await app.login(credentials: Credentials.anonymous) // Create a configuration to open the seed user's realm var config = seedUser.configuration(partitionValue: "Partition You Want to Bundle") config.objectTypes = [Todo.self] // Open the realm with the seed user's config let realm = try await Realm(configuration: config, downloadBeforeOpen: .always) print("Successfully opened realm: \(realm)") // Verify there is a todo object in the realm whose // owner's name is "Daenerys". When we open the bundled // realm later, we should see the same result. let todos = realm.objects(Todo.self) let daenerysTodos = todos.where { $0.owner == "Daenerys" } XCTAssertEqual(daenerysTodos.count, 1) // Specify an output directory for the bundled realm // We're using FileManager here for tested code examples, // but this could be a static directory on your computer. guard let outputDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return } // Append a file name to complete the path let bundleRealmFilePath = outputDir.appendingPathComponent("seed.realm") // Update the config file path to the path where you want to save the bundled realm config.fileURL = bundleRealmFilePath // Check to see if there is already a realm at the bundled realm file path. If there // is already a realm there, delete it. if Realm.fileExists(for: config) { try Realm.deleteFiles(for: config) print("Successfully deleted existing realm at path: \(bundleRealmFilePath)") } else { print("No file currently exists at path") } // Write a copy of the realm at the URL we specified try realm.writeCopy(configuration: config) // Verify that we successfully made a copy of the realm XCTAssert(FileManager.default.fileExists(atPath: bundleRealmFilePath.path)) print("Successfully made a copy of the realm at path: \(bundleRealmFilePath)") // Verify that opening the realm at the new file URL works. // Don't download changes, because this can mask a copy // that does not contain the expected data. let copiedRealm = try await Realm(configuration: config, downloadBeforeOpen: .never) print("Successfully opened realm: \(realm)") // Verify that the copied realm contains the data we expect let copiedTodos = copiedRealm.objects(Todo.self) let daenerysCopiedTodos = copiedTodos.where { $0.owner == "Daenerys" } XCTAssertEqual(daenerysCopiedTodos.count, 1) print("Copied realm opens and contains this many tasks: \(daenerysCopiedTodos.count)") }
writeCopy(configuration: ) compacta automaticamente seu Realm no menor tamanho possível antes de copiar.
Observação
Diferenças entre domínios sincronizados e domínios somente locais
O exemplo acima utiliza um SyncConfiguration
para configurar um realm sincronizado. Para criar uma cópia de um realm local, configure seu realm com RealmConfiguration
.
Agrupe um arquivo Realm em seu aplicativo de produção
Agora que você tem uma cópia do domínio que contém os dados iniciais, agrupe-o com seu aplicativo de produção. Em um nível amplo, isso implica:
Crie um novo projeto com os mesmos modelos de dados exatos que seu aplicativo de produção. Abra um domínio e adicione os dados que deseja agrupar. Como os arquivos realm são multiplataforma, você pode fazer isso em um aplicativo macOS.
Arraste a cópia compactada do seu arquivo de área para o Xcode Project Navigator do seu aplicativo de produção.
Go para a aba Build Phases do destino do aplicativo no Xcode. Adicione o arquivo de domínio à fase de construção Copy Bundle Resources .
Neste ponto, seu aplicativo pode acessar o arquivo de Realm agrupado. Encontre seu caminho com Bundle.main.path(forResource:ofType).
Você pode abrir o domínio diretamente no caminho do pacote se a propriedade readOnly
estiver definida como true
no Realm.Configuration. Se você deseja modificar o domínio agrupado, primeiro copie o arquivo agrupado para a pasta Documentos do seu aplicativo com a configuração seedFilePath
com a URL do domínio Realm em sua Configuração.
Dica
Veja o aplicativo de amostra de migração para um aplicativo de trabalho completo que usa um domínio local agrupado.
Abrir um Realm a partir de um arquivo de Realm agrupado
Agora que você tem uma cópia do domínio incluída em seu aplicativo de produção, precisa adicionar código para usá-lo. Use o método seedFilePath ao configurar seu domínio para abrir o domínio a partir do arquivo agrupado:
Dica
Se a sua aplicação acessar Realm em um contexto do async/await
, marque o código com @MainActor
para evitar falhas relacionadas a threading.
try await openBundledSyncedRealm() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func openBundledSyncedRealm() async throws { let app = App(id: YOUR_APP_SERVICES_APP_ID) // Log in an app user who will use the bundled realm let user = try await app.login(credentials: Credentials.anonymous) // Create a configuration for the app user's realm // This should use the same partition value as the bundled realm var newUserConfig = user.configuration(partitionValue: "Partition You Want to Bundle") newUserConfig.objectTypes = [Todo.self] // Find the path of the seed.realm file in your project let realmURL = Bundle.main.url(forResource: "seed", withExtension: ".realm") print("The bundled realm URL is: \(realmURL)") // When you use the `seedFilePath` parameter, this copies the // realm at the specified path for use with the user's config newUserConfig.seedFilePath = realmURL // Open the synced realm, downloading any changes before opening it. // This starts with the existing data in the bundled realm, but checks // for any updates to the data before opening it in your application. let realm = try await Realm(configuration: newUserConfig, downloadBeforeOpen: .always) print("Successfully opened the bundled realm") // Read and write to the bundled realm as normal let todos = realm.objects(Todo.self) // There should be one todo whose owner is Daenerys because that's // what was in the bundled realm. var daenerysTodos = todos.where { $0.owner == "Daenerys" } XCTAssertEqual(daenerysTodos.count, 1) print("The bundled realm has \(daenerysTodos.count) todos whose owner is Daenerys") // Write as usual to the realm, and see the object count increment let todo = Todo(value: ["name": "Banish Ser Jorah", "owner": "Daenerys", "status": "In Progress"]) try realm.write { realm.add(todo) } print("Successfully added a todo to the realm") daenerysTodos = todos.where { $0.owner == "Daenerys" } XCTAssertEqual(daenerysTodos.count, 2) }
Observação
Diferenças entre domínios sincronizados e domínios somente locais
O exemplo acima utiliza um SyncConfiguration
para configurar um realm sincronizado. Para criar uma cópia de um realm local, configure seu realm com Realm.Configuration
.