レコードに対する変更を通知するよう登録

レコードに変更が起こっていないか定期的に問い合わせ、ほとんどは前回と同じであることを確かめているに過ぎない、という状況は、効率的とは言えません。代わりに、レコードが変更されたら通知するようサーバに登録し、あとはバックグラウンドでクエリを処理させるとよいでしょう。サーバは、レコードに所定の変更が施されれば、アプリケーションに通知します。たとえば、特定のアーティストのアートワークに関心があるユーザーは、該当するアートワークがアップロードされたとき、アプリケーションに通知が届くようにすることができます。

../Art/subscriptions_2x.png

サブスクリプションをデータベースに保存する

レコード型、プレディケート、通知を求める変更の種類を指定する、サブスクリプションオブジェクトを生成して、データベースに保存します。

サブスクリプションを生成、保存するには

  1. プレディケートオブジェクトを生成します。

    たとえば、「特定のアーティストのアートワーク」という指定が考えられます(Artworkレコード型のartistReference型であると想定)。

    CKRecordID *artistRecordID = [[CKRecordID alloc] initWithRecordName:@"Mei Chen"];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"artist = %@", artistRecordID];
  2. レコード型、プレディケート、通知オプションを指定して、サブスクリプションを生成します。

    CKSubscription *subscription = [[CKSubscription alloc]
                                        initWithRecordType:@"Artwork"
                                        predicate:predicate
                                        options:CKSubscriptionOptionsFiresOnRecordCreation];

    引数optionsには、CKSubscriptionOptionsFiresOnRecordCreationCKSubscriptionOptionsFiresOnRecordDeletionCKSubscriptionOptionsFiresOnRecordUpdateCKSubscriptionOptionsFiresOnceを指定できます。引数optionsはビットマスクなので、変更の種類をいくつでも組み合わせて指定可能です。たとえばCKSubscriptionOptionsFiresOnRecordCreation | CKSubscriptionOptionsFiresOnRecordUpdateoptions:引数として指定すれば、新規データが現れる都度、すべて通知を受け取ることになります。

  3. CloudKit通知オブジェクトを生成します。

    CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
    notificationInfo.alertLocalizationKey = @"New artwork by your favorite artist.";
    notificationInfo.shouldBadge = YES;

    ローカライズした文字列を画面に表示したい場合は、通知のalertLocalizationKeyプロパティに適切な値を指定してください(alertBodyプロパティではありません)。

  4. サブスクリプションの通知オブジェクトとして、ここで生成した、CloudKitの通知オブジェクトを設定します。

    subscription.notificationInfo = notificationInfo;
  5. サブスクリプションをデータベースに保存します。

    CKDatabase *publicDatabase = [[CKContainer defaultContainer] publicCloudDatabase];
        [publicDatabase saveSubscription:subscription
                        completionHandler:^(CKSubscription *subscription, NSError *error) {
                            if (error)
                                // insert error handling
                        }
         ];

Xcode上でアプリケーションを実行すると、サブスクリプションがデータベースに保存されます。

プッシュ通知を送るよう登録する

サブスクリプションをデータベースに保存しても、それだけで通知が届くようにはなりません。CloudKitは「Apple Push Notificationサービス(Apple Push Notification service(APNs))」を使ってサブスクリプション通知をアプリケーションに送るようになっているので、プッシュ通知を受け取れるよう登録する必要があるのです。

iOSまたはtvOSのアプリケーションであれば、次のようなコードをapplication:didFinishLaunchingWithOptions:プロトコルメソッドに追加することにより、プッシュ通知が届くよう登録します。

    // Register for push notifications
    UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
    [application registerUserNotificationSettings:notificationSettings];
    [application registerForRemoteNotifications];

Macアプリケーションの場合はapplicationDidFinishLaunching:プロトコルメソッドを実装して登録します。

いずれの場合も、application:didRegisterForRemoteNotificationsWithDeviceToken:メソッドやapplication:didFailToRegisterForRemoteNotificationsWithError:メソッドを実装することにより、プッシュ通知を受け取る旨が正常に登録できた場合、あるいは失敗した場合に、適切なアクションを実行できます。

プッシュ通知に対処するコードを記述する

次にapplication:didReceiveRemoteNotification:メソッドを実装して、サブスクリプション通知が届いたときに対処できるようにします。iOSおよびtvOSのアプリケーションならばUIApplicationDelegateプロトコルメソッド、MacアプリケーションであればNSApplicationDelegateプロトコルメソッドを実装してください。たとえば、所定のプレディケートに合致するレコードが生成、更新、削除されたとき、ビューを更新する、という処理が考えられます。

  1. application:didReceiveRemoteNotification:プロトコルメソッドを、アプリケーションのデリゲートに追加します。

    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    }
  2. application:didReceiveRemoteNotification:メソッドではまず、引数userInfoCKNotificationオブジェクトに変換します。

    CKNotification *cloudKitNotification = [CKNotification notificationFromRemoteNotificationDictionary:userInfo];
  3. 通知の本体を取得します。

    NSString *alertBody = cloudKitNotification.alertBody;
  4. CKQueryNotificationオブジェクトから、追加または更新されたレコードを取得します。

    if (cloudKitNotification.notificationType == CKNotificationTypeQuery) {
       CKRecordID *recordID = [(CKQueryNotification *)cloudKitNotification recordID];
    }
  5. レコードの変更内容に応じて、ビューを更新し、あるいはユーザーに通知します。

サブスクリプションをテストする

サブスクリプションのテストは、まず、Xcode上でアプリケーションを実行して実施します。この状態で、CloudKit Dashboardを使ってレコードを生成、更新、削除し、通知が届くことを確認してください(「レコードを追加、変更、削除する」を参照)。続いて、複数のデバイス上でアプリケーションを実行し、充分にサブスクリプションをテストしてください。あるデバイス上で変更を施し、別のデバイスにサブスクリプション通知が届くかどうか確認するのです。通知の発信元と同じデバイスに通知が届くことはないので、複数のデバイスが必要です。

iOSおよびtvOSの場合、サブスクリプション通知のテストには、(シミュレータを使うのではなく)Macに接続されたデバイスを使ってください。通知を受け取る許可を求めるダイアログが現れれば、プッシュ通知を正常に登録できたことになります。

まとめ

この章では次の事項を解説しました。