Subscriptionとはデータが変更されたタイミングをPushで受け取ることが出来る仕組み。
実はCloudKitは、Record Zoneの種類によって利用出来るSubscriptionが違う。
Subscriptionを使わない場合でも、ここを理解すること、Record Zoneの設計方法が少し見えてくるはず。
Subscriptionの種類
Subscriptionには以下の3種類がある。
Subscription | 対応する差分取得Operation |
---|---|
CKDatabaseSubscription | CKFetchDatabaseChangesOperation |
CKRecordZoneSubscription | CKFetchRecordZoneChangesOperation |
CKQuerySubscription | CKFetchNotificationChangesOperation |
第一回: CloudKit(1): DatabaseとRecord で説明したように、Record Zone には Default と Custom, Shared の3つの種類がある。それらのRecord ZoneごとのSubscription利用可・不可をマトリックスにすると以下になる。
Public DB | Private DB | Shared DB | ||
---|---|---|---|---|
Default Zone | Default Zone | Custom Zone | Shared Zone | |
CKDatabaseSubscription | × | × | ○ | ○ |
CKRecordZoneSubscription | × | × | ○ | × |
CKQuerySubscription | ○ | ○ | ○ | × |
前回の差分の取得のところで、さらっと 「Default Zone以外」と書いた。
じゃぁDefault Zone では差分取得ができないのか?
Default Zoneで差分を取得するには、CKQuerySubscription を利用できる....のだが....
CKFetchNotificationChangesOperation が iOS11 で deprecated になってしまった。
代わりにCKDatabaseSubscription, CKFetchDatabaseChangesOperation, CKFetchRecordZoneChangesOperation を使えとなっていますが、これらはDefault Zoneでは使えない。
詳しい調査はしていませんが、もし方法がないのであれば、Default Zoneでの差分取得はできなくなった(?)
関連: Apple Developer Forum: Notifications in iOS 11
ほかにも、CKFetchRecordChangesOperation がiOS10で deprecated になっているのをみると、Tokenを使ったRecord差分取得は、 CKFetchRecordZoneChangesOperation のみに限定...言い換えると、「Default Zone 以外で全件対象のみ可能」とする方向なのかもしれない?
(あくまで個人の感想)
以上の情報から、
Private DBでデータ量が多いものは特に、Custom Zone にしておくのが無難と思った。Customは選択肢が多いので状況に合わせていろいろ選択しやすい。
2014年のWWDC: Advanced CloudKit で、Custom ZoneはAtomic Commits ができるよ とも言っているし、なんか、ほかにも色々ありそうだ。
そして、可能な限り、Custom Zone は複数に分けておくとよさそう。
(Zoneが違うRecordを一気に更新することはできないので注意)
Default Zoneを使う場合は、一回のQueryが適切な件数になるようUIやIndexをうまく設計する というところだろうか。
さらに、Public DBの場合は、競合がなるべく起こらないような設計が大事そうだ。
ちなみに、Record Zoneの変更があると、DatabaseSubscriptionにも通知が届く。
そのため、Record Zoneの変更トリガーはCKDatabaseSubscription か CKRecordZoneSubscription のどちらかを登録していればOK。
アプリ利用中にRecord Zoneが増減するのであれば、CKDatabaseSubscription を使い、CKRecordZoneSubscriptionは使わない という選択もアリ。
Subscriptionの登録
3つのSubscription、ともに、CK***Subscriptionを作成し、CKModifySubscriptionsOperation で登録していく。DatabaseSubscriptionの登録例
CKRecordZoneSubscriptionはZoneIDを、CKQuerySubscriptionは対象のRecord Type, NSPredicate(条件),タイミング(作成、変更、削除時)などを指定できる。
通知を受ける
通常のPush通知と同様、registerForRemoteNotifications しておいて、UIApplicationのdidReceiveRemoteNotification にて取得する。通知設定の登録 通知の受信
Database, RecordZone のSubscriptionの受けには、前回の記事で書いた、Tokenを使った差分の取得をすれば良い。(※1)
CKQueryNotificationは、対象のRecordIDが取得できるが、通知が必ず届くとは保証されないので、そのRecordを最新にすれば全て最新の状態になるとは言えない。
だが、前述したように、通知の差分を取得するためのCKFetchNotificationChangesOperationがdeprecatedになったので、差分の取得をせずCKQueryOperationで検索かけて最新になるようするのが良さそうだ。
終わりに
SubscriptionはCloudKitを理解するための大きな山場だと思う。当初、私はCustom Zoneを、「Defaultではない自由に作れるZone」 というイメージしか持っていなかったので混乱した。こんなに機能が違うのかと。
この記事の内容をざっくり理解してから、ドキュメントやサンプルコードをみると理解し易いのではないかと思う。
次回はShareについて書く予定!
※1
以下は、CKDatabaseSubscriptionで通知を受けた時、Record Zoneも一緒に反映する例としてもう少し詳しく書いたもの。長いので文中からは削除したがせっかくなのでペタリ。