Docs 菜单
Docs 主页
/ /
Atlas Device SDKs
/ /

基于分区的同步 - Swift SDK

在此页面上

  • 打开基于分区的 Sync Realm
  • 将非同步 Realm 作为同步 Realm 打开
  • 将同步 Realm 作为非同步 Realm 打开
  • 从基于分区的同步迁移到 Flexible Sync
  • 迁移后更新客户端代码

基于分区的同步是一种较旧的模式,用于将 Atlas Device Sync 与 Realm Swift SDK 结合使用。 我们建议对新应用使用Flexible Sync 。 此页面上的信息适用于仍在使用基于分区的同步的用户。

提示

Realm Swift SDK v 10.40.0及更高版本能力从基于分区的同步迁移到 Flexible Sync。 有关更多信息,请参阅: 从基于分区的同步迁移到 Flexible Sync。

有关基于分区的同步以及如何在Atlas App Services中配置该同步的更多信息,请参阅App Services文档中的基于分区的同步

当您为后端应用配置选择基于分区的同步时,您的客户端实施必须包含分区值。 这是您在配置基于分区的同步时选择的分区键字段的值。

分区值决定客户端应用程序可以访问哪些数据。

您可以在打开同步 Realm 时传入分区值。

使用同步配置初始化同步 Realm。 这样,您就可以指定一个分区值,其数据应同步到 Realm。

首次登录并打开同步域时,您需要登录用户,并将用户的RLMSyncConfiguration对象以及所需的partitionValue传递给+[RLMKRealm realmWithConfiguration:error:]。

这将在设备上打开一个同步域 。 该域尝试在背景与您的应用同步,以检查服务器上的更改,或上传用户所做的更改。

RLMApp *app = [RLMApp appWithId:YOUR_APP_ID];
// Log in...
RLMUser *user = [app currentUser];
NSString *partitionValue = @"some partition value";
RLMRealmConfiguration *configuration = [user configurationWithPartitionValue:partitionValue];
NSError *error = nil;
RLMRealm *realm = [RLMRealm realmWithConfiguration:configuration
error:&error];
if (error != nil) {
NSLog(@"Failed to open realm: %@", [error localizedDescription]);
// handle error
} else {
NSLog(@"Opened realm: %@", realm);
// Use realm
}

将具有所需 分区值 的已登录用户的 配置 对象传递给 Realm 初始化程序。

您可以选择指定域是否应在打开之前下载更改。如果您未指定下载行为,这将打开一个包含设备上数据的 域,并尝试在背景同步更改。

let app = App(id: YOUR_APP_SERVICES_APP_ID)
// Store a configuration that consists of the current user,
// authenticated to this instance of your app. If there is no
// user, your code should log one in.
let user = app.currentUser
let partitionValue = "some partition value"
var configuration = user!.configuration(partitionValue: partitionValue)
// Open the database with the user's configuration.
let syncedRealm = try! Realm(configuration: configuration)
print("Successfully opened the synced realm: \(syncedRealm)")

版本 10.23.0 中的新增功能

如果您希望非同步 Realm 开始与其他设备和Atlas App Services后端同步,您可以使用writeCopy(configuration: )方法复制非同步 Realm,以便与同步配置一起使用。 下面的示例创建了一个非同步 Realm 文件的副本,其中包含所有现有数据,您可以将其与同步配置一起使用。

复制用于同步的 Realm 后,您可以将该副本作为同步 Realm 打开。 您对同步域所做的任何更改都将反映在同步Realm文件中,并且这些更改还会传播到其他设备和App Services后端。

注意

仅限基于分区的同步

此方法仅支持在非同步 Realm 和基于分区的同步之间进行转换。如果应用程序使用“灵活同步”,则必须手动遍历一个 Realm 中的对象,并将其复制到另一个 Realm。

提示

如果您的应用会在 async/await 上下文中访问 Realm,请使用 @MainActor 来标记此代码,从而避免出现与线程相关的崩溃。

try await convertLocalRealmToSyncedRealm()
// Opening a realm and accessing it must be done from the same thread.
// Marking this function as `@MainActor` avoids threading-related issues.
@MainActor
func convertLocalRealmToSyncedRealm() async throws {
let app = App(id: YOUR_APP_SERVICES_APP_ID)
// Log in the user whose realm you want to open as a synced realm
let syncUser = try await app.login(credentials: Credentials.anonymous)
// Create a configuration to open the sync user's realm
var syncConfig = syncUser.configuration(partitionValue: "Your Partition Value")
syncConfig.objectTypes = [QsTask.self]
// Prepare the configuration for the user whose local realm you
// want to convert to a synced realm
var localConfig = Realm.Configuration()
localConfig.objectTypes = [QsTask.self]
// For this example, add some data to the local realm
// before copying it. No need to do this if you're
// copying a realm that already contains data.
let localRealm = addExampleData(config: localConfig)
// Create a copy of the local realm that uses the
// sync configuration. All the data that is in the
// local realm is available in the synced realm.
try! localRealm.writeCopy(configuration: syncConfig)
// Open the synced realm we just created from the local realm
let syncedRealm = try await Realm(configuration: syncConfig)
// Access the Task objects in the synced realm to see
// that we have all the data we expect
let syncedTasks = syncedRealm.objects(QsTask.self)
var frodoSyncedTasks = syncedTasks.where { $0.owner == "Frodo" }
XCTAssertEqual(frodoSyncedTasks.count, 3)
print("Synced realm opens and contains this many tasks: \(frodoSyncedTasks.count)")
// Add a new task to the synced realm, and see it in the task count
let task4 = QsTask(value: ["name": "Send gift basket to Tom Bombadil", "owner": "Frodo"])
try! syncedRealm.write {
syncedRealm.add(task4)
}
frodoSyncedTasks = syncedTasks.where { $0.owner == "Frodo" }
XCTAssertEqual(frodoSyncedTasks.count, 4)
print("After adding a task, the synced realm contains this many tasks: \(frodoSyncedTasks.count)")
// Open the local realm, and confirm that it still only contains 3 tasks
let openedLocalRealm = try await Realm(configuration: localConfig)
let localTasks = openedLocalRealm.objects(QsTask.self)
let frodoLocalTasks = localTasks.where { $0.owner == "Frodo" }
XCTAssertEqual(frodoLocalTasks.count, 3)
print("Local realm opens and contains this many tasks: \(frodoLocalTasks.count)")
XCTAssertNotEqual(frodoLocalTasks.count, frodoSyncedTasks.count)
/// Populate the local realm with some data that we'll use in the synced realm.
func addExampleData(config: Realm.Configuration) -> Realm {
// Prepare the configuration for the user whose local realm you
// want to convert to a synced realm
let localConfig = config
// Open the local realm, and populate it with some data before returning it
let localRealm = try! Realm(configuration: localConfig)
let task1 = QsTask(value: ["name": "Keep it secret", "owner": "Frodo"])
let task2 = QsTask(value: ["name": "Keep it safe", "owner": "Frodo"])
let task3 = QsTask(value: ["name": "Journey to Bree", "owner": "Frodo"])
try! localRealm.write {
localRealm.add([task1, task2, task3])
}
return localRealm
}
}

版本 10.23.0 中的新增功能

提示

如果您不想将同步 Realm 永久更改为非同步 Realm,则可以暂停同步会话。 请参阅:暂停或恢复同步会话。

如果要永久停止 Realm 同步到Atlas App Services后端,您可以使用writeCopy(configuration: )方法复制已同步 Realm,以便与非同步配置一起使用。 以下示例在您指定的文件 URL 中创建 Realm 文件的副本,其中包含所有现有数据。

此进程会删除本地 Realm 中的realm_id 。 您必须递增模式版本,就像删除属性一样。

复制 Realm 以便在不同步的情况下使用后,您可以将该副本作为非同步 Realm 打开。 您对非同步 Realm 所做的任何更改仅反映在本地 Realm 文件中。 任何更改都不会传播到其他设备或 App Services 后端。

注意

仅限基于分区的同步

此方法仅支持在非同步 Realm 和基于分区的同步之间进行转换。如果应用程序使用“灵活同步”,则必须手动遍历一个 Realm 中的对象,并将其复制到另一个 Realm。

提示

如果您的应用会在 async/await 上下文中访问 Realm,请使用 @MainActor 来标记此代码,从而避免出现与线程相关的崩溃。

try await convertSyncedRealmToLocalRealm()
// Opening a realm and accessing it must be done from the same thread.
// Marking this function as `@MainActor` avoids threading-related issues.
@MainActor
func convertSyncedRealmToLocalRealm() async throws {
let app = App(id: YOUR_APP_SERVICES_APP_ID)
// Log in the user whose realm you want to open as a local realm
let syncUser = try await app.login(credentials: Credentials.anonymous)
// Create a configuration to open the seed user's realm
var syncConfig = syncUser.configuration(partitionValue: "Some Partition Value")
syncConfig.objectTypes = [QsTask.self]
// Open the realm with the Sync user's config, downloading
// any remote changes before opening.
let syncedRealm = try await Realm(configuration: syncConfig, downloadBeforeOpen: .always)
print("Successfully opened realm: \(syncedRealm)")
// Verify the data we expect in the realm
// The synced realm we are copying contains 3 tasks whose owner is "Frodo"
let syncedTasks = syncedRealm.objects(QsTask.self)
var frodoSyncedTasks = syncedTasks.where { $0.owner == "Frodo" }
XCTAssertEqual(frodoSyncedTasks.count, 3)
print("Synced realm opens and contains this many tasks: \(frodoSyncedTasks.count)")
// Construct an output file path for the local Realm
guard let outputDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
// Append a file name to complete the path
let localRealmFilePath = outputDir.appendingPathComponent("local.realm")
// Construct a local realm configuration
var localConfig = Realm.Configuration()
localConfig.objectTypes = [QsTask.self]
localConfig.fileURL = localRealmFilePath
// `realm_id` will be removed in the local realm, so we need to bump
// the schema version.
localConfig.schemaVersion = 1
// Check to see if there is already a realm at the local realm file path. If there
// is already a realm there, delete it.
if Realm.fileExists(for: localConfig) {
try Realm.deleteFiles(for: localConfig)
print("Successfully deleted existing realm at path: \(localRealmFilePath)")
} else {
print("No file currently exists at path")
}
// Make a copy of the synced realm that uses a local configuration
try syncedRealm.writeCopy(configuration: localConfig)
// Try opening the realm as a local realm
let localRealm = try await Realm(configuration: localConfig)
// Verify that the copied realm contains the data we expect
let localTasks = localRealm.objects(QsTask.self)
var frodoLocalTasks = localTasks.where { $0.owner == "Frodo" }
XCTAssertEqual(frodoLocalTasks.count, 3)
print("Local realm opens and contains this many tasks: \(frodoLocalTasks.count)")
let task = QsTask(value: ["name": "Send gift basket to Tom Bombadil", "owner": "Frodo"])
try! localRealm.write {
localRealm.add(task)
}
frodoLocalTasks = localTasks.where { $0.owner == "Frodo" }
XCTAssertEqual(frodoLocalTasks.count, 4)
print("After adding a task, the local realm contains this many tasks: \(frodoLocalTasks.count)")
frodoSyncedTasks = syncedTasks.where { $0.owner == "Frodo" }
XCTAssertEqual(frodoSyncedTasks.count, 3)
print("After writing to local realm, synced realm contains this many tasks: \(frodoSyncedTasks.count)")
XCTAssertNotEqual(frodoLocalTasks.count, frodoSyncedTasks.count)
}

您可以将 App Services Device Sync 模式从基于分区的同步迁移到 Flexible Sync。 迁移是一个自动过程,无需对应用程序代码进行任何更改。 自动迁移需要 Realm Swift SDK 版本 10.40.0 或更高版本。

通过迁移,您可以保留现有的 App Services 用户和身份验证配置。 Flexible Sync提供更通用的权限配置选项和更细粒度的数据同步。

有关如何将App Services App从基于分区的同步迁移到Flexible Sync的更多信息,请参阅迁移Device Sync模式。

从基于分区的同步自动迁移到Flexible Sync不需要对客户端代码进行任何更改。 但是,为了支持此功能,Realm 会通过以下方式自动处理两种同步模式之间的差异:

  • 自动为每个Realm 对象类型创建Flexible Sync订阅,其中partitionKey == partitionValue

  • partitionKey字段注入到每个对象中(如果尚不存在)。 这是自动Flexible Sync订阅所必需的。

如果您需要在迁移后更新客户端代码,请考虑更新客户端代码库以删除隐藏的迁移功能。 在以下情况下,您可能需要更新客户端代码库:

  • 您在客户端代码库中添加新模型或更改模型

  • 添加或更改涉及读取或写入 Realm 对象的功能

  • 您希望对同步的数据实施更细粒度的控制

进行以下更改,将基于分区的同步客户端代码转换为使用 Flexible Sync:

  • 切换到打开同步域flexibleSyncConfiguration()

  • 将相关属性添加到对象模型中,以便在 Flexible Sync 订阅中使用。 例如,您可以添加ownerId属性,使用户能够仅同步自己的数据。

  • 删除自动Flexible Sync订阅并手动创建相关订阅。

有关 Flexible Sync 权限策略的示例,包括如何为这些策略进行数据建模的示例,请参阅Device Sync权限指南。

当您从基于分区的同步迁移到Flexible Sync时,Realm 会自动为您的应用创建隐藏的Flexible Sync订阅。 下次添加或更改订阅时,我们建议您:

  1. 删除自动生成的订阅。

  2. 在客户端代码库中手动添加相关订阅。

这样,您就可以在代码库中同时查看所有订阅逻辑,以便将来进行迭代和调试。

有关自动生成的Flexible Sync订阅的更多信息,请参阅将客户端应用程序迁移到Flexible Sync。

后退

将数据流式传输至 Atlas