Realms sincronizados
You can configure a realm to automatically synchronize data between many devices that each have their own local copy of the data. Synced realms use a different configuration than local-only realms and require an Atlas App Services backend to handle the synchronization process.
Las aplicaciones siempre pueden crear, modificar y eliminar objetos de dominio sincronizados localmente, incluso sin conexión. Siempre que haya una conexión de red disponible, el SDK de dominio abre una conexión con un servidor de aplicaciones y sincroniza los cambios con y desde otros clientes. El protocolo Atlas Device Sync y las transformaciones operativas del lado del servidor garantizan que todas las instancias totalmente sincronizadas de un reino vean exactamente los mismos datos, incluso si algunos cambios ocurrieron sin conexión y/o se recibieron fuera de orden.
Tip
Learn How to Configure and Use Sync
For more information on Device Sync, including directions on how to set up sync in an App Services app, see Sync Data.
Synced Realms vs. Non-Synced Realms
Los realms sincronizados difieren de los realms locales no sincronizados en algunos aspectos:
Synced realms attempt to sync changes with your backend App Services App, whereas non-synced realms do not.
Synced realms can be accessed by authenticated users, while non-synced realms have no concept of users or authentication.
Con los dominios sincronizados, puedes especificar el comportamiento de descarga para descargar actualizaciones antes de abrir un dominio. Sin embargo, para solicitar que se descarguen los cambios antes de abrir el dominio, el usuario debe estar conectado. Los dominios no sincronizados siempre se pueden usar sin conexión.
Puedes copiar datos de un dominio no sincronizado a uno sincronizado y viceversa, pero no puedes sincronizar un dominio no sincronizado. Para convertir un dominio no sincronizado en uno sincronizado, sigue el proceso descrito en "Migrar una aplicación solo local a una aplicación sincronizada".
For more information about how to configure and open a non-synced realm, refer to: Configure & Open a Realm - Swift SDK.
Open a Synced Realm
Tip
For information about opening a Partition-Based Sync realm, refer to Open a Partition-Based Sync Realm.
El flujo típico para abrir un reino sincronizado implica:
Creando una configuración de sincronización.
Abrir el realm sincronizado del usuario con la configuración.
Durante la autenticación, almacenamos en caché las credenciales del usuario en un sync_metadata.realm
archivo en el dispositivo.
When you open a synced realm after authenticating, you can bypass the login flow and go directly to opening the synced realm, using the same sync configuration you already created.
With cached credentials, you can:
Open a synced realm immediately with the data that is on the device. You can use this method offline or online.
Open a synced realm after downloading changes from your App. This requires the user to have an active internet connection.
When you use Flexible Sync, use the flexibleSyncConfiguration() to open a synced realm.
Tip
If your app accesses Realm in an async/await context, mark the code with @MainActor to avoid threading-related crashes.
let realm = try await openFlexibleSyncRealm() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func openFlexibleSyncRealm() async throws -> Realm { let app = App(id: APPID) let credentials = emailPasswordCredentials(app: app) let user = try await app.login(credentials: credentials) var config = user.flexibleSyncConfiguration() // Pass object types to the Flexible Sync configuration // as a temporary workaround for not being able to add complete schema // for a Flexible Sync app config.objectTypes = [Task.self, Team.self] let realm = try await Realm(configuration: config, downloadBeforeOpen: .always) print("Successfully opened realm: \(realm)") return realm }
Importante
Flexible Sync Requiere una suscripción
Si tu aplicación utiliza Device Sync bidireccional estándar, no puedes usar un realm de Flexible Sync hasta que añadas al menos una suscripción. Para aprender a agregar suscripciones, consulta: Agregar una suscripción.
Esto no se aplica a la ingesta de datos. No se puede crear una suscripción para un.AsymmetricObject
Open a Synced Realm In Memory
New in version 10.46.0.
You can open a synced database entirely in memory, which does not create a .realm file or its associated auxiliary files. Instead the SDK stores objects in memory while the realm is open and discards them immediately when all instances are closed.
Para abrir un realm sincronizado en memoria, establece la propiedad inMemoryIdentifier de la configuración del realm como un identificador de string.
// Instantiate the app and get a user. let app = App(id: APPID) let user = try await app.login(credentials: Credentials.anonymous) // Create a configuration. var configuration = user.flexibleSyncConfiguration() configuration.objectTypes = [Task.self, Team.self] // Specify an in-memory identifier for the configuration. configuration.inMemoryIdentifier = "YOUR-IDENTIFIER-STRING" // Open a Realm with this configuration. let realm = try await Realm(configuration: configuration) print("Successfully opened realm: \(realm)") // Add subscriptions and work with the realm
Open a Synced Realm as a Different Sync User
New in version 10.23.0.
Si quieres abrir un realm sincronizado como un usuario Sync diferente, puedes usar el método writeCopy(configuración: ) para hacer una copia del realm sincronizado y usarla con la nueva configuración de sincronización del usuario. El siguiente ejemplo crea una copia del realm sincronizado, con todos sus datos existentes, que puedes usar con una configuración de sincronización diferente.
Después de copiar el reino para la configuración del nuevo usuario de sincronización, puede abrir la copia como un reino sincronizado para ese usuario.
Nota
Solo sincronización de mismo tipo
This method only supports copying a Partition-Based Sync configuration for another Partition-Based Sync user, or a Flexible Sync configuration for another Flexible Sync user. You cannot use this method to convert between a Partition-Based Sync realm and a Flexible Sync realm or vice-versa.
Tip
If your app accesses Realm in an async/await context, mark the code with @MainActor to avoid threading-related crashes.
try await convertSyncedRealmForAnotherUser() // Opening a realm and accessing it must be done from the same thread. // Marking this function as `@MainActor` avoids threading-related issues. func convertSyncedRealmForAnotherUser() async throws { let app = App(id: YOUR_APP_SERVICES_APP_ID) // Log in the user whose realm you want to use with another sync user let frodoBaggins = try await app.login(credentials: Credentials.anonymous) var frodoConfig = frodoBaggins.configuration(partitionValue: "Some Partition Value") frodoConfig.objectTypes = [QsTask.self] // Open the synced realm, and confirm it contains the data we want // the other user to be able to access. let frodoRealm = try await Realm(configuration: frodoConfig, downloadBeforeOpen: .always) let frodoRealmTasks = frodoRealm.objects(QsTask.self) let frodoSyncedTasks = frodoRealmTasks.where { $0.owner == "Frodo" } XCTAssertEqual(frodoSyncedTasks.count, 3) print("Successfully opened frodo's realm and it contains this many tasks: \(frodoSyncedTasks.count)") // Log in as the user who will work with frodo's synced realm let samwiseGamgee = try await app.login(credentials: Credentials.anonymous) var samConfig = samwiseGamgee.configuration(partitionValue: "Some Partition Value") samConfig.objectTypes = [QsTask.self] // Specify an output directory for the copied realm // We're using FileManager here for tested code examples. guard let outputDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return } // Append a file name to complete the path let copiedRealmFilePath = outputDir.appendingPathComponent("copied.realm") // Update the config file path to the path where you want to save the copied realm samConfig.fileURL = copiedRealmFilePath // Make a copy of frodo's realm that uses sam's config try frodoRealm.writeCopy(configuration: samConfig) // Open sam's realm, and see that it contains the same data as frodo's realm let samRealm = try await Realm(configuration: samConfig) let samRealmTasks = samRealm.objects(QsTask.self) var samSyncedTasks = samRealmTasks.where { $0.owner == "Frodo" } print("Successfully opened sam's realm and it contains this many tasks: \(samSyncedTasks.count)") XCTAssertEqual(frodoSyncedTasks.count, samSyncedTasks.count) // Add a task to sam's realm let task = QsTask(value: ["name": "Keep an eye on that Gollum", "owner": "Sam"]) try! samRealm.write { samRealm.add(task) } // See that the new task reflects in sam's realm, but not frodo's samSyncedTasks = samRealmTasks.where { $0.owner == "Sam" } XCTAssertEqual(samSyncedTasks.count, 1) let samTasksInFrodoRealm = frodoRealmTasks.where { $0.owner == "Sam" } XCTAssertEqual(samTasksInFrodoRealm.count, 0) }
Open a Synced Realm with Swift Concurrency Features
You can open a synced realm as an actor-isolated realm using Swift concurrency features:
func mainThreadFunction() async throws { // Initialize the app client and authenticate a user let app = App(id: APPID) let user = try await app.login(credentials: Credentials.anonymous) // Configure the synced realm var flexSyncConfig = user.flexibleSyncConfiguration(initialSubscriptions: { subs in subs.append(QuerySubscription<Todo>(name: "all_todos"))}) flexSyncConfig.objectTypes = [Todo.self] // Open and use the synced realm let realm = try await Realm(configuration: flexSyncConfig, actor: MainActor.shared, downloadBeforeOpen: .always) try await useTheSyncedRealm(realm: realm) }
For more information about working with actor-isolated realms, refer to Use Realm with Actors - Swift SDK.
Descargar cambios antes de abrir
New in version 10.15.0.
Cuando abras un realm sincronizado con el Swift SDK, puedes pasar el parámetro downloadBeforeOpen para especificar si deseas descargar el conjunto de cambios de tu aplicación antes de abrir el realm. Este parámetro acepta un caso de la enumeración OpenBehavior:
never: Immediately open the realm on the device. Download changes in the background when the user has internet, but don't block opening the realm.always: Verifica los cambios cada vez que se abra el realm. Requiere que el usuario tenga una conexión a Internet activa.once: Download data before opening a realm for the first time, but open it without downloading changes on subsequent opens. This lets you populate a realm with initial data, but enables offline-first functionality on subsequent opens.
Tip
If your app accesses Realm in an async/await context, mark the code with @MainActor to avoid threading-related crashes.
func getRealmAfterDownloadingUpdates() async throws -> Realm { let app = App(id: APPID) let user = try await app.login(credentials: Credentials.anonymous) var configuration = user.flexibleSyncConfiguration() configuration.objectTypes = [FlexibleSync_Task.self, FlexibleSync_Team.self] let realm = try await Realm(configuration: configuration, downloadBeforeOpen: .always) print("Successfully opened realm after downloading: \(realm)") return realm } let realm = try await getRealmAfterDownloadingUpdates() print("The open realm is: \(realm)") // Add subscription and work with the realm
Open a Synced Realm Offline
Cuando tu aplicación Realm autentica a un usuario, almacena en caché las credenciales del usuario. Puedes comprobar si existen credenciales de usuario para omitir el flujo de inicio de sesión y acceder al usuario almacenado en caché. Usa esto para abrir un realm sin conexión.
Nota
El inicio de sesión inicial requiere una conexión de red
Cuando un usuario se registra en tu aplicación o inicia sesión por primera vez con una cuenta existente en un cliente, este debe tener conexión de red. Comprobar las credenciales de usuario en caché permite abrir un reino sin conexión, pero solo si el usuario ha iniciado sesión previamente con conexión.
Solo puedes abrir un reino sincronizado sin conexión si no necesitas que tu aplicación cliente always descargue los cambios antes de abrir el reino.
Tip
If your app accesses Realm in an async/await context, mark the code with @MainActor to avoid threading-related crashes.
// Log the user into the backend app. // The first time you login, the user must have a network connection. func getUser() async throws -> User { // Check for an existing user. // If the user is offline but credentials are // cached, this returns the existing user. if let user = app.currentUser { return user } else { // If the device has no cached user // credentials, log them in. let app = App(id: YOUR_APP_SERVICES_APP_ID) let loggedInUser = try await app.login(credentials: Credentials.anonymous) return loggedInUser } } let user = try await getUser() var configuration = user.configuration(partitionValue: "Some Partition Value") // Open a Realm with this configuration. // If you do not require the app to download updates // before opening the realm, the realm just opens, even if // offline. let realm = try await Realm(configuration: configuration) print("Successfully opened realm: \(realm)")