我有一条从设备 A 共享到设备 B 的记录。设备 B 接受共享并在设备 B 的 UI 上显示信息。设备 B 使用 CKDatabaseSubscription 订阅该共享记录上的数据库更改。
然后我删除设备 A 上的该记录,然后触发设备 B 关于数据库更改的通知。然后,我通过使用 CKFetchDatabaseChangesOperation 获取数据库更改来处理设备 B 上的通知。然后我随后使用 CKFetchRecordZoneChangesOperation 获取区域更改。
我接到了 recordZoneFetchCompletionBlock 和 fetchRecordZoneChangesCompletionBlock 的电话,但就是这样。既没有调用 recordChangedBlock 也没有调用 recordWithIDWasDeletedBlock。
重要的是要注意我正在使用这个完全相同的代码来监视另一种类型的共享记录并且它可以工作。它实际上是一个记录,是这个记录中一个孩子的孩子。所以我不确定为什么这个顶级/父记录在查询时不会显示为被删除。当设备 A 删除记录时(在其私有数据库和设备 B 的共享数据库上),该记录确实会从 CloudKit 中删除。因此,我不相信这不是 CloudKit 上的任何关系或限制。
欢迎任何想法如何追逐这个。在这里待了一个星期。
这是我用来订阅的代码...
+ (void) subscribeToGameChangesInDB:(int)dbID success:(void (^) (void))success failure:(void (^)(NSError *error))failure
{
CKNotificationInfo *notif = [[CKNotificationInfo alloc] init];
notif.alertLocalizationKey = @"DB Changed";
notif.shouldBadge = NO;
notif.shouldSendContentAvailable = YES;
CKDatabase *db = [CloudKitManager getDBForIdentifier:dbID];
if (dbID == kCKDBPublic)
{
NSLog(@"ERROR : Cannot subscribe to database changes in the PUBLIC DB.");
}
else
{
CKDatabaseSubscription *subscription = [[CKDatabaseSubscription alloc] initWithSubscriptionID:[NSString stringWithFormat:@"AllDBhanges-%@", [CloudKitManager getDatabaseNameForScope:db.databaseScope]]];
subscription.notificationInfo = notif;
[CloudKitManager saveSubscription:subscription inDB:db success:success failure:failure];
}
}
+ (void) saveSubscription:(CKSubscription*)subscription inDB:(CKDatabase*)db success:(void (^) (void))success failure:(void (^)(NSError *error))failure
{
[db saveSubscription:subscription completionHandler:^(CKSubscription * _Nullable subscription, NSError * _Nullable error)
{
if (error)
{
if ((error.code == CKErrorServerRejectedRequest) || (error.code == CKErrorUnknownItem)) // We probably already subscribed from another device.
{
NSLog(@"Already Subscribed... Passing Success. (code:%ld)", (long)error.code);
success ();
}
else
{
failure (error);
}
}
else
{
success();
}
}];
}
这是我用来处理通知并执行上述两个操作的代码。
- (void) handleDatabaseNotification:(CKDatabaseNotification*)dbNotif
{
CKDatabase *db = [self getDatabaseForNotificationDatabaseScope:dbNotif.databaseScope];
[self handleDatabase:db changesWithPreviousChangeToken:[self getServerDBChangeTokenFromDisk] withCompletion:^(NSError * _Nonnull error) {
if (error)
{
NSLog (@"ERROR : HAndling Database change notificiation : %@", error);
}
}];
}
- (void) handleDatabase:(CKDatabase*)db changesWithPreviousChangeToken:(CKServerChangeToken*)previousChangeToken withCompletion:(void (^)(NSError *error))completion
{
CKFetchDatabaseChangesOperation *operation = [[CKFetchDatabaseChangesOperation alloc] initWithPreviousServerChangeToken:previousChangeToken];
[operation setRecordZoneWithIDChangedBlock:^(CKRecordZoneID * _Nonnull zoneID) {
NSLog(@"ZONE CHANGE : %@", zoneID);
[self handleDatabase:db zoneID:zoneID changesWithPreviousChangeToken:[self getServerZonesChangeTokenFromDisk]];
}];
[operation setFetchDatabaseChangesCompletionBlock:^(CKServerChangeToken * _Nullable serverChangeToken, BOOL moreComing, NSError * _Nullable operationError) {
if (operationError)
{
NSLog (@"ERROR : Unable to fetch Zone changes : %@", operationError);
completion(operationError);
}
NSLog(@"New serverChangeToken : %@", serverChangeToken);
[self storeServerDBChangeTokenToDisk:serverChangeToken];
if (moreComing)
{
[self handleDatabase:db changesWithPreviousChangeToken:serverChangeToken withCompletion:completion];
}
else
completion (nil);
}];
[db addOperation:operation];
}
- (void) handleDatabase:(CKDatabase*)db zoneID:(CKRecordZoneID*)zoneID changesWithPreviousChangeToken:(CKServerChangeToken*)previousChangeToken
{
NSLog(@"Zone Changes. DB : %@\nzoneID : %@", db, zoneID);
CKFetchRecordZoneChangesConfiguration *config = [[CKFetchRecordZoneChangesConfiguration alloc] init];
config.previousServerChangeToken = previousChangeToken;
CKFetchRecordZoneChangesOperation *zoneOperation = [[CKFetchRecordZoneChangesOperation alloc] initWithRecordZoneIDs:@[zoneID] configurationsByRecordZoneID:@{zoneID: config}];
[zoneOperation setRecordZoneFetchCompletionBlock:^(CKRecordZoneID * _Nonnull recordZoneID, CKServerChangeToken * _Nullable serverChangeToken, NSData * _Nullable clientChangeTokenData, BOOL moreComing, NSError * _Nullable recordZoneError) {
if (recordZoneError)
{
NSLog(@"ERROR : recordZoneError : %@", recordZoneError);
}
else
{
[self storeServerZonesChangeTokenToDisk:serverChangeToken];
if (moreComing)
{
NSLog(@"*********** There's MORE COMING ***************");
[self handleDatabase:db zoneID:zoneID changesWithPreviousChangeToken:serverChangeToken];
}
/* Handle changes */
}
}];
[zoneOperation setRecordChangedBlock:^(CKRecord * _Nonnull record) {
[self handleDatabaseRecordChange:record];
}];
[zoneOperation setFetchRecordZoneChangesCompletionBlock:^(NSError * _Nullable operationError) {
NSLog (@"setFetchRecordZoneChangesCompletionBlock");
if (operationError)
NSLog (@"setFetchRecordZoneChangesCompletionBlock ERROR : %@", operationError);
}];
[zoneOperation setRecordZoneChangeTokensUpdatedBlock:^(CKRecordZoneID * _Nonnull recordZoneID, CKServerChangeToken * _Nullable serverChangeToken, NSData * _Nullable clientChangeTokenData) {
NSLog(@"setRecordZoneChangeTokensUpdatedBlock Called : \n\nserverChangeToken = %@\n\nclientChangeTokenData = %@\n", serverChangeToken, clientChangeTokenData);
}];
[zoneOperation setRecordWithIDWasDeletedBlock:^(CKRecordID * _Nonnull recordID, CKRecordType _Nonnull recordType) {
NSManagedObjectContext *context = [self.coreManager getContext];
[context performBlockAndWait:^{
[self handleDeleteRecordID:recordID recordType:recordType];
[self.coreManager deleteContext:context];
}];
}];
[db addOperation:zoneOperation];
}