パーティションベースの同期 - Swift SDK
項目一覧
Partition-Based Sync is an older mode for using Atlas Device Sync with the Realm Swift SDK. 新しいアプリにはFlexible Syncを使用することをお勧めします。 このページの情報は、パーティションベースの同期を引き続き使用しているユーザー向けです。
Tip
Realm Swift SDK v 10.40.0以降では、パーティションベースの同期から Flexible Sync に移行する機能がサポートされています。 詳細については、「 パーティションベースの同期から Flexible Sync への移行 」を参照してください。
パーティションベースの同期 と Atlas App Services でのパーティションベースの同期の構成方法について詳しくは、Atlas App Services ドキュメントの「パーティションベースの同期 」を参照してください。
パーティションベースの同期Realmを開く
バックエンド アプリ構成にパーティションベースの同期を選択する場合、クライアント実装にはパーティション値を含める必要があります。 これは、 Flexible Sync を設定するときに選択したパーティションキーフィールドの値です。
パーティション値によって、クライアント アプリケーションがアクセスできるデータが決まります。
同期された Realm を開くときに、パーティション値を渡します。
同期された Realm を同期構成で初期化します。 これにより、Realm に同期するデータのパーティション値を指定できます。
同期された Realm を初めてログインして開くと、ユーザーがログインし、ユーザーのRMSyncConfigurationオブジェクトと目的のパーティション値が+[RMRealm RealmWithConfiguration:error:] に渡されます。
これにより、デバイス上で同期された Realm が開きます。 Realm はバックグラウンドでアプリと同期して、サーバー上の変更を確認したり、ユーザーが行った変更をアップロードしたりします。
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 初期化ツールに渡します。
オプションで、 を開く前に、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)")
同期されていない Realm を同期済み Realm として開く
バージョン 10.23.0 の新機能。
同期されていない Realm で他のデバイスや App Services バックエンドとの同期を開始する場合は、 writeCopy(config: )メソッドを使用して、同期構成で使用するために同期されていない Realm のコピーを作成できます。 以下の例では、同期構成で使用できる既存のすべてのデータを含む、同期されていない Realm ファイルのコピーを作成します。
Sync で使用する Realm をコピーした後、同期された Realm としてそのコピーを開くことができます。 同期された Realm に加えた変更は同期された Realm ファイルに反映され、他のデバイスや App Services バックエンドにも反映されます。
注意
パーティションベースの同期のみ
このメソッドは、非同期 Realm と パーティションベースの同期 との間の変換のみをサポートします。 アプリで Flexible Sync を使用する場合は、一方の Realm 内のオブジェクトを手動で反復処理し、もう一方の Realm にコピーする必要があります。
Tip
アプリが 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. 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 } }
同期された Realm を非同期 Realm として開く
バージョン 10.23.0 の新機能。
Tip
同期された Realm を同期されていない Realm に永続的に変更したくない場合は、同期セッションを一時的に一時停止できます。 「同期セッションの一時停止または再開 」を参照してください。
App Services バックエンドへの同期を永続的に停止する場合は、 writeCopy(config: )メソッドを使用して、同期された Realm のコピーを作成し、非同期構成で使用できます。 以下の例では、指定されたファイル URL に、既存のすべてのデータを含む Realm ファイルのコピーを作成します。
このプロセスにより、ローカル Realm 内のrealm_id
が削除されます。 プロパティを削除した場合と同様に、スキーマ バージョンを増やす必要があります。
同期なしで使用する Realm をコピーした後、そのコピーを同期されていない Realm として開くことができます。 同期されていない Realm に加えた変更は、ローカル Realm ファイルにのみ反映されます。 変更は、他のデバイスまたは App Services バックエンドに伝達されません。
注意
パーティションベースの同期のみ
このメソッドは、非同期 Realm と パーティションベースの同期 との間の変換のみをサポートします。 アプリで Flexible Sync を使用する場合は、一方の Realm 内のオブジェクトを手動で反復処理し、もう一方の Realm にコピーする必要があります。
Tip
アプリが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. 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) }
パーティションベースの同期から Flexible Sync への移行
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 は 2 つの同期モード間の違いを次の方法で自動的に処理します。
partitionKey == partitionValue
の各オブジェクトタイプの Flexible Sync サブスクリプションを自動的に作成します。すべてのオブジェクトに
partitionKey
フィールドを挿入します(フィールドがまだ存在しない場合)。 これは自動 Flexible Sync サブスクライブに必要です。
If you need to make updates to your client code after migration, consider updating your client codebase to remove hidden migration functionality. 次の場合には、クライアント コードベースを更新する必要がある場合があります。
クライアント コードベースで新しいモデルを追加または変更する
Realm オブジェクトの読み取りまたは書き込みを含む機能を追加または変更する場合
同期するデータの内容をより詳細に制御する機能を実装したい
Flexible Sync を使用するようにパーティションベースの同期クライアント コードを変換するには、次の変更を行います。
同期された Realm を開く
flexibleSyncConfiguration()
に切り替えます。Flexible Sync サブスクライブで使用する関連プロパティをオブジェクトモデルに追加します。 たとえば、ユーザーが自分のデータのみを同期できるようにするには、
ownerId
プロパティを追加します。自動 Flexible Sync サブスクライブを削除し、関連するサブスクライブを手動で作成します。
これらの戦略にデータをモデル化する方法の例を含む、Flexible Sync 権限戦略の例については、 Device Sync 権限ガイド を参照してください。
サブスクリプションの削除と手動作成
パーティションベースの同期から Flexible Sync に移行すると、Realm はアプリ用の非表示の Flexible Sync サブスクリプションを自動的に作成します。 次回サブスクリプションを追加または変更するときは、次の操作を行うことをお勧めします。
これにより、将来の反復やデバッグのために、すべてのサブスクライブ ロジックをコードベースにまとめて表示できます。
自動生成される Flexible Sync サブスクライブの詳細については、「クライアント アプリの Flexible Sync への移行 」を参照してください。