1

我有一条从设备 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];
}
4

2 回答 2

0

假设您有一个 id 为“John”的区域,并且您只有一条记录,如果该记录被删除,您将不会收到recordWithIDWasDeletedBlock,但您会收到recordZoneWithIDWasDeletedBlock

这意味着该区域“John”不再有任何记录,并且不再存在,因此被删除。

但是,如果您在区域“John”中有更多记录并且您从中删除了一条记录,那么您将收到recordWithIDWasDeletedBlock.

于 2020-08-16T10:47:29.087 回答
0

我遇到这个问题已经有一段时间了,所以细节很模糊。但我为此向一位 Apple 工程师开了一张支持票。

它的网络(就像 2018 年一样)是,当 a 的父记录CKShare被删除并且该记录与您共享时,您只会收到数据库更改通知。您对该记录的访问已结束,因此没有关于它的记录级信息。

我问工程师是否有办法知道记录是否被删除或取消共享或为什么会更改,他说没有办法知道。

所以我认为处理这个问题的方法是推断该记录不可访问,然后重新查询它。然后你就会知道它是否可用。

于 2020-07-29T20:37:57.690 回答