Sponsor Link
環境&対象
- maxOS Catalina 10.15.7
- Xcode 12.3
- iOS 14.2
前回は、CoreData を Realm に置き換えて動かしてみました。
[SwiftUI][CoreData] SwiftUI と MVVM で始める CoreData 入門 (その14:CoreData を Realm と入れ替え)
今回は、CoreData 版を拡張して、iCloud 同期できるようにします。
CloudKit を使った開発をするには、Apple Developer Program への加入が必要です。
iCloud 同期
複数のデバイスで同じデータを使うためには、2種類の方法があります。
1つ目は、iCloud 上にドキュメントファイルを置き、複数のデバイスから開く方法です。
アプリを Document App で作成すると実現できます。
しかし、CoreData と相性は良くないです。
[SwiftUI] Document App の隠れた制約(FileDocument の制約)
もう1つの方法が今回実装する CloudKit を使う方法です。アプリが自動的に iCloud と同期してくれます。
NSPersistentCloudKitContainer
NSPersistentContainer の CloudKit 対応版です。
Apple のドキュメントは、こちら。
NSPersistentContainer の代わりに、NSPersistentCloudKitContainer を使うことで、自動的に iCloud と Sync されます。
こちらを読みなさいと書いてあるドキュメントは、流れがわかるという点では良いのですが、細かな相違点がいろいろ発生しているので注意してください。
プロジェクト設定
CloudKit 対応するためには、プロジェクトの設定も追加する必要があります。
Apple のドキュメントには、こちら を読みなさいと書いてあります。
Xcode 等にもアップデートが入っているので、実際の作業は 説明と少し異なります。
この段階で、”Signing & Capability” で “Automatically manage signing” をチェックしておく必要があります。
Xcode12.3 では、以下の手順となります。
既存の CoreData プロジェクトを CloudKit 対応させるための プロジェクト設定変更の手順です。
- CloudKit 対応させるターゲットに、Capability “iCloud” を追加します。
- 追加された “iCloud” capability を設定します。CloudKit をチェックして、+ ボタンをクリックします。
- 使用する Container を設定 通常は、iCloud.逆DNS.App名 というようなコンテナ名を使用するようです。
- Container に設定されていることを確認
- “Background Modes” の “Remote notification” を有効化 ”iCloud” と同様に、”Background Modes” を追加し、”Remote notifications” を有効にします。
- Apple ドキュメントには、”default container” という表現がありますが、Xcode11 で廃止されたようです。
- Push Notification は、CloudKit を有効にすると自動で設定されるようです(@Xcode12.3)
上記の操作を行うことで、CloutKit 上に、CoreData で使用するスキーマに相当する CloudKit 側のスキーマを作成してくれます。
CloudKit Dashboard で確認することができます。
Capability の iCloud 設定に表示されていた “CloudKit Dashboard” を押下すると、Web 上での CloudKit Dashboard に移動できます。
CloudKit Dashboard
ログインすると、以下のような画面になります。
先ほど設定したコンテナが作成されていることが確認できます。
この画面を使って、デバイスで行った変更が iCloud 上に反映されているかを確認することができます。
recordName に Queryable を設定しておくと便利
System Fields の recordName を Queryable 設定にしておくと便利です(recordName で検索できるようにするという意味です)。
以下、その設定方法です。
- CloudKit Dashboard 画面で、Schema をクリック
- Edit Indexes をクリック
- Add Index をクリック
- recordName に QUERYABLE を設定して保存
この設定を行なっておくと、RecordName (CoreData での Entity) でデータを検索することができるようになります。
NSPersistentContainer 置き換え
準備ができたので、NSPersistentCloudKitContainer に置き換えていきます。
本当に置き換えるだけです。
struct TODOItemStore : TODOItemStoreProtocol {
static let logger = Logger(subsystem: "com.smalldesksoftware.MyTODO.TODOItemStore", category: "TODOItemStore")
let container: NSPersistentContainer
init(_ inMemory:Bool ) {
// container = NSPersistentContainer(name: "MyTODO")
container = NSPersistentCloudKitContainer(name: "MyTODO")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
// .. snip ..
NSPersistentCloudKitContainer は、NSPersistentContainer を継承して定義されていますので、実際にインスタンス化する箇所以外は、変更が不要です。
これだけで、Cloud と同期できるなんて素晴らしいですね。
CloudKit 上で確認
CloudKit 上にスキーマが作成されていることは確認しましたが、いくつかデータを作成して実際に同期させてみましょう。
- シミュレータで、iCloud アカウント設定を行う
- シミュレータ上のアプリで、要素をいくつか作成する
iCloud アカウント設定を行わないと、(当然ですが) 同期は行われません。
先ほども使った、”CloudKit Dashboard” に移動して、作成された要素を確認しましょう。
- Data へ移動
- Query Records をクリックすると 保存されている Record が表示され、左側の三角を押すと、各レコードの詳細が表示されます。
こうすることで、デバイスで作成されたデータが、Cloud に 同期されていることが確認できます。
別デバイスで確認
別のシミュレータで アプリを起動してしばらく待つと、データが同期されることを確認できます。
# 別シミュレータでの iCloud 設定を忘れずに
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link