🎉

CKSyncEngineでデータをiCloudに同期する

2024/01/06に公開

WWDC23で発表されたCloudKitの新API

https://developer.apple.com/videos/play/wwdc2023/10188/

デバイスのローカルにあるデータとCloudKit(iCloud)の双方向な同期処理を簡単に実現できる機能

同期が必要な例としてはWeb→iPad→iPhone間で同じデータを更新したりとか

サンプルコード

このアプリではローカルに保存しているContacts.jsonの読み書きをCloudKitのRecordと同期する

https://github.com/apple/sample-cloudkit-sync-engine

let container: CKContainer = CKContainer(identifier: "iCloud.com.apple.samples.cloudkit.SyncEngine")
let dataURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appending(component: "Contacts").appendingPathExtension("json")
let appDataBlob = try Data(contentsOf: dataURL)
let appData = AppData()
var configuration = CKSyncEngine.Configuration(
    database: container.privateCloudDatabase,
    stateSerialization: appData.stateSerialization,
    delegate: self
)
configuration.automaticallySync = true
let syncEngine = CKSyncEngine(configuration)

AppDataやContactはDataModelで定義された構造体

delegateはCKSyncEngineDelegateを実装したクラス、システムに非同期で呼び出される

同期処理のハンドリング

syncEngine.state.add()して変更したRecordを送信するのが基本的な方法

https://github.com/apple/sample-cloudkit-sync-engine/blob/63d9d16d75429a94d06d77f6dac13cb9a777b09f/SyncEngine/SyncedDatabase.swift#L338-L351

delegateのhandleFetchedRecordZoneChanges()で受け取った変更をContacts.jsonに保存する

https://github.com/apple/sample-cloudkit-sync-engine/blob/63d9d16d75429a94d06d77f6dac13cb9a777b09f/SyncEngine/SyncedDatabase.swift#L153-L182

handleSentRecordZoneChanges()はマージ競合の解決

https://github.com/apple/sample-cloudkit-sync-engine/blob/63d9d16d75429a94d06d77f6dac13cb9a777b09f/SyncEngine/SyncedDatabase.swift#L203

syncEngine.state.add(.deleteZone)して削除

https://github.com/apple/sample-cloudkit-sync-engine/blob/63d9d16d75429a94d06d77f6dac13cb9a777b09f/SyncEngine/SyncedDatabase.swift#L386-L393

CKSyncEngineじゃないもの

CKDatabaseSubscription+APNsで自作

https://github.com/apple/sample-cloudkit-privatedb-sync

CKSyncEngineのアーキテクチャはこれと同様だと思う

NSPersistentCloudKitContainer

Core DataのストレージをCloudKitにミラーリングするやつ

https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud

ローカルにあるDBがCore Dataならこっちで代用できる

SwiftData+CloudKit

SwiftDataの基盤はCore DataなのでCloudKitへの同期をオプトインできる

https://medium.com/@jakir/sync-swiftdata-with-icloud-using-cloudkit-34764a46ba54

Discussion