ioscloudkitcksubscription

How can each iCloud user save a user specific subscription in CloudKit?


I’m having an issue creating subscriptions in a public CloudKit database. The code works fine when saving the subscription for the first iCloud user but fails trying to save a slightly different subscription against the same record type for a second iCloud user.

Here is the code that saves the subscription (answers in Swift are fine too):

CKNotificationInfo *info = [[CKNotificationInfo alloc] init];
info.shouldSendContentAvailable = YES;

CKReference *ref = [[CKReference alloc] initWithRecordID:_ckUserID action:CKReferenceActionNone];
NSPredicate *pred = [NSPredicate predicateWithFormat:@"user == %@", ref];
NSString *subId = [NSString stringWithFormat:@"access-%@", _ckUserID.recordName];

CKSubscription *sub = [[CKSubscription alloc] initWithRecordType:@"access" predicate:pred subscriptionID:subId options:CKSubscriptionOptionsFiresOnRecordCreation | CKSubscriptionOptionsFiresOnRecordUpdate | CKSubscriptionOptionsFiresOnRecordDeletion];
sub.zoneID = [CKRecordZone defaultRecordZone].zoneID;
sub.notificationInfo = info;

CKModifySubscriptionsOperation *op = [[CKModifySubscriptionsOperation alloc] initWithSubscriptionsToSave:@[ sub ] subscriptionIDsToDelete:nil];
op.modifySubscriptionsCompletionBlock = ^(NSArray<CKSubscription *> *savedSubscriptions, NSArray<NSString *> *deletedSubscriptionIDs, NSError *operationError) {
    if (operationError) {
        RMLogError(@"Error trying to update user's access subscription: %@", operationError);
    } else {
        RMLogInfo(@"User access subscription added");
    }
};
[_ckdatabase addOperation:op];

_ckUserID is a CKRecordID representing the current iCloud user.
_ckdatbase is a CKDatabase reference to the public database of the current CloudKit container.

When this code is run on Device A with User A, the subscription is saved just fine.

When this code is then run on Device B with User B, the subscription fails with the following message in the log:

2016-04-19 11:38:42:504 MyApp[560:f03] Error trying to update user's access subscription: <CKError 0x147830530: "Partial Failure" (2/1011); "Failed to modify some subscriptions"; uuid = 98E9F99A-C4F6-4488-8087-45285A7C1DB1; container ID = "iCloud.com.blah.MyApp"; partial errors: { access-_df09e8908eeb9b9f12ebbe935e389d51 = <CKError 0x14664b4e0: "Unknown Item" (11/2003); server message = "did not find required record type: _sub_trigger_sub_08b399dc1448e58993a967b704a07ee0"> }>

The access record type has a user field that is a reference to a CKRecordID representing an iCloud user id.

My goal here is to have a subscription for each user that allows the app to know whenever a record specific to the current user is added, updated, or deleted from this table.

Why can’t I save a 2nd subscription, from a 2nd user, for this record type? I’m even giving each subscription its own unique id based on the user id.


Solution

  • I created a simple test app to replicate this problem and of course it worked just fine in my test app.

    I went back to my real app and after some digging I got this issue resolved. I did two things:

    1. In the CloudKit Dashboard I deleted all existing Subscription Types.
    2. I fixed a bug in my code where I was mistakenly setting the subscription's zoneID to the defaultRecordZone. Though not really related to the posted problem, this bug was preventing notifications from reaching devices unless the device was logged into the same iCloud account used to add/update/delete the record.

    Basically this was some strange error that was fixed by resetting some things in the Dashboard and restarting the app.