๋ฌธ์„œ ๋ฉ”๋‰ด
๋ฌธ์„œ ํ™ˆ
/ /
Atlas Device SDK
/ /

ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™” - Swift SDK

์ด ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ

  • ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™” Realm ์—ด๊ธฐ
  • ๋™๊ธฐํ™”๋˜์ง€ ์•Š์€ Realm์„ ๋™๊ธฐํ™”๋œ Realm์œผ๋กœ ์—ด๊ธฐ
  • ๋™๊ธฐํ™”๋œ Realm์„ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์€ Realm์œผ๋กœ ์—ด๊ธฐ
  • ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”์—์„œ Flexible Sync๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
  • ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ›„ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ์—…๋ฐ์ดํŠธ

ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”๋Š” Realm Swift SDK์™€ ํ•จ๊ป˜ Atlas Device Sync๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ด์ „ ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค. ์ƒˆ ์•ฑ์—๋Š” Flexible Sync ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด ํŽ˜์ด์ง€์˜ ์ •๋ณด๋Š” ์•„์ง ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํŒ

Realm Swift SDK v10.40.0 and newer supports the ability to migrate from Partition-Based Sync to Flexible Sync. For more information, refer to: Migrate from Partition-Based Sync to Flexible Sync.

ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™” ๋ฐ Atlas App Services์—์„œ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ App Services ๋ฌธ์„œ์—์„œ ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™” ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ฐฑ์—”๋“œ ์•ฑ ๊ตฌ์„ฑ์— ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™” ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„์— ํŒŒํ‹ฐ์…˜ ๊ฐ’์ด ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ ์„ ํƒํ•˜๋Š” ํŒŒํ‹ฐ์…˜ ํ‚ค ํ•„๋“œ์˜ ๊ฐ’์ž…๋‹ˆ๋‹ค.

ํŒŒํ‹ฐ์…˜ ๊ฐ’์— ๋”ฐ๋ผ ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค.

๋™๊ธฐํ™”๋œ ์˜์—ญ์„ ์—ด ๋•Œ ํŒŒํ‹ฐ์…˜ ๊ฐ’์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

๋™๊ธฐํ™” ๊ตฌ์„ฑ ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™๊ธฐํ™”๋œ Realm์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์˜์—ญ๊ณผ ๋™๊ธฐํ™”ํ•ด์•ผ ํ•˜๋Š” ํŒŒํ‹ฐ์…˜ ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ ๋กœ๊ทธ์ธํ•˜์—ฌ ๋™๊ธฐํ™”๋œ Realm์„ ์—ด๋ฉด ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์ธํ•˜๊ณ  ์›ํ•˜๋Š” partitionValue ๊ฐ€ ์žˆ๋Š” ์‚ฌ์šฉ์ž์˜ RLMSyncConfiguration ๊ฐ์ฒด๋ฅผ +[RLMRealm realmWithConfiguration:error:]์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์žฅ์น˜์—์„œ ๋™๊ธฐํ™”๋œ ์˜์—ญ์ด ์—ด๋ฆฝ๋‹ˆ๋‹ค. 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
}

์›ํ•˜๋Š” ํŒŒํ‹ฐ์…˜ ๊ฐ’ ์ด ํฌํ•จ๋œ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ๊ตฌ์„ฑ ๊ฐ์ฒด๋ฅผ ์˜์—ญ ์ด๋‹ˆ์…œ๋ผ์ด์ €์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

์˜์—ญ์„ ์—ด๊ธฐ ์ „์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋‹ค์šด๋กœ๋“œํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ ํƒ์ ์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์šด๋กœ๋“œ ๋™์ž‘์„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์žฅ์น˜์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋œ ์˜์—ญ์ด ์—ด๋ฆฌ๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ๋™๊ธฐํ™”๋ฅผ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

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 ํŒŒ์ผ์— ๋ฐ˜์˜๋˜๋ฉฐ ๋‹ค๋ฅธ ์žฅ์น˜์™€ 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์ด Atlas App Services ๋ฐฑ์—”๋“œ์— ๋™๊ธฐํ™”๋˜๋Š” ๊ฒƒ์„ ์˜๊ตฌ์ ์œผ๋กœ ์ค‘์ง€ํ•˜๋ ค๋ฉด writeCopy(configuration: ) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ๊ตฌ์„ฑ์— ์‚ฌ์šฉํ•  ๋™๊ธฐํ™”๋œ Realm์˜ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ์—์„œ๋Š” ์ง€์ •ํ•œ ํŒŒ์ผ URL์— ๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋œ Realm ํŒŒ์ผ์˜ ๋ณต์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด ํ”„๋กœ์„ธ์Šค๋Š” ๋กœ์ปฌ ์˜์—ญ์—์„œ realm_id ์„(๋ฅผ) ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์†์„ฑ์„ ์‚ญ์ œํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์Šคํ‚ค๋งˆ ๋ฒ„์ „์„ ์ฆ๊ฐ€์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋™๊ธฐํ™” ์—†์ด ์‚ฌ์šฉํ•  ์˜์—ญ์„ ๋ณต์‚ฌํ•œ ํ›„์—๋Š” ๋ณต์‚ฌ๋ณธ์„ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์€ ์˜์—ญ์œผ๋กœ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋™๊ธฐํ™”๋˜์ง€ ์•Š์€ 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 Realm Mobile Sync ๋ชจ๋“œ๋ฅผ ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”์—์„œ Flexible Sync๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ์ž๋™ ํ”„๋กœ์„ธ์Šค์ž…๋‹ˆ๋‹ค. ์ž๋™ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Realm Swift SDK ๋ฒ„์ „ 10.40.0 ์ด์ƒ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋ฉด ๊ธฐ์กด App Services ์‚ฌ์šฉ์ž ๋ฐ ์ธ์ฆ ๊ตฌ์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Flexible Sync๋Š” ๋”์šฑ ๋‹ค์–‘ํ•œ ๊ถŒํ•œ ๊ตฌ์„ฑ ์˜ต์…˜๊ณผ ๋ณด๋‹ค ์„ธ๋ถ„ํ™”๋œ ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™”๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

App Services App์„ ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”์—์„œ Flexible Sync๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Device Sync ๋ชจ๋“œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์ฐธ์กฐํ•˜์„ธ์š”.

ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”์—์„œ Flexible Sync๋กœ ์ž๋™ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ๋•Œ๋Š” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด Realm์€ ๋‹ค์Œ์„ ํ†ตํ•ด ๋‘ ๋™๊ธฐํ™” ๋ชจ๋“œ์˜ ์ฐจ์ด์ ์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • partitionKey == partitionValue ์ธ ๊ฐ Realm ๊ฐ์ฒด ์œ ํ˜•์— ๋Œ€ํ•ด Flexible Sync ๊ตฌ๋…์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • ํ•„๋“œ๊ฐ€ ์•„์ง ์—†๋Š” ๊ฒฝ์šฐ ๋ชจ๋“  ๊ฐ์ฒด์— partitionKey ํ•„๋“œ๋ฅผ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ž๋™ Flexible Sync ๊ตฌ๋…์— ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ›„ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ์ˆจ๊ฒจ์ง„ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ธฐ๋Šฅ์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์ƒˆ ๋ชจ๋ธ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ชจ๋ธ์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ

  • Realm ๊ฐ์ฒด๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์“ฐ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ

  • ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‹ค ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•˜๋ ค๋Š” ๊ฒฝ์šฐ

ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ Flexible Sync๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€ํ™˜ํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•˜์„ธ์š”.

  • ๋™๊ธฐํ™”๋œ Realm์„ ์—ฌ๋Š” flexibleSyncConfiguration() ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • Flexible Sync ๊ตฌ๋…์— ์‚ฌ์šฉํ•  ๊ด€๋ จ ์†์„ฑ์„ ๊ฐ์ฒด ๋ชจ๋ธ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ownerId ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ž์‹ ์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ž๋™ Flexible Sync ๊ตฌ๋…์„ ์ œ๊ฑฐํ•˜๊ณ  ๊ด€๋ จ ๊ตฌ๋…์„ ์ˆ˜๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ „๋žต์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ๋ง ๋ฐฉ๋ฒ•์˜ ์˜ˆ๋ฅผ ํฌํ•จํ•˜์—ฌ Flexible Sync ๊ถŒํ•œ ์ „๋žต์˜ ์˜ˆ๋Š” Device Sync ๊ถŒํ•œ ๊ฐ€์ด๋“œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

ํŒŒํ‹ฐ์…˜ ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”์—์„œ Flexible Sync๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋ฉด Realm์€ ์•ฑ์— ๋Œ€ํ•œ ์ˆจ๊ฒจ์ง„ Flexible Sync ๊ตฌ๋…์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์— ๊ตฌ๋…์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•  ๋•Œ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

  1. ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ ๊ตฌ๋…์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

  2. ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๊ด€๋ จ ๊ตฌ๋…์„ ์ˆ˜๋™์œผ๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ํ–ฅํ›„ ๋ฐ˜๋ณต ๋ฐ ๋””๋ฒ„๊น…์„ ์œ„ํ•ด ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ๋ชจ๋“  ๊ตฌ๋… ๋กœ์ง์„ ํ•จ๊ป˜ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ Flexible Sync ๊ตฌ๋…์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ํด๋ผ์ด์–ธํŠธ ์•ฑ์„ Flexible Sync๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์ฐธ์กฐํ•˜์„ธ์š”.

๋Œ์•„๊ฐ€๊ธฐ

Atlas๋กœ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆฌ๋ฐ

๋‹ค์Œ

Xcode ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ์—์„œ Realm