阅读背景:

CloudKit:根据CKQueryNotification删除本地对象

来源:互联网 

I'm building an app that heavily relies on CloudKit for data synchronization. Each time the app launches, it catches up with all changes that have been made on the server using a CKFetchNotificationChangesOperation. This successfully returns all objects that have been created and/or modified, but I am now at the stage that I also want my app to delete records based on these messages.

我正在构建一个严重依赖CloudKit进行数据同步的应用程序。每次应用程序启动时,它都会捕获使用CKFetchNotificationChangesOperation在服务器上进行的所有更改。这会成功返回已创建和/或修改的所有对象,但我现在处于我希望我的应用程序根据这些消息删除记录的阶段。

In my app, each object that I have stored in CoreData also carries the recordID of the online representation of that object. This way I can easily pick up objects I need to modify.

在我的应用程序中,我存储在CoreData中的每个对象也携带该对象的在线表示的recordID。这样我就可以轻松获取需要修改的对象。

This seems hard when deleting objects, as CloudKit only returns recordID's for these objects, and does not provide a recordType that I can use to know what object I am looking for in my CoreData Database.

删除对象时这似乎很难,因为CloudKit只返回这些对象的recordID,并且不提供我可以用来知道我在CoreData数据库中查找的对象的recordType。

Question

How does one correctly handle CloudKit 'deleted' notifications in a case with multiple record types?

在具有多种记录类型的情况下,如何正确处理CloudKit“已删除”通知?

2 个解决方案

#1


3  

If CloudKit doesn't give you any indication of the type of record that was deleted, it's kind of a pain to deal with. You can't delete objects in Core Data without knowing the entity type, so if CloudKit doesn't give you any clues then you need to check every entity that could have the recordId.

如果CloudKit没有给出任何已删除记录类型的指示,那么处理起来就很麻烦。在不知道实体类型的情况下,您无法删除Core Data中的对象,因此如果CloudKit没有为您提供任何线索,那么您需要检查每个可能具有recordId的实体。

The delete process is the same as usual with Core Data. Do a fetch request with a predicate of something like `recordId = %@" to find a matching object. If you find one, delete it. Except that you have to repeat this for each potential entity.

删除过程与Core Data一样。使用类似`recordId =%@的谓词执行获取请求以查找匹配的对象。如果找到,请删除它。除非您必须为每个潜在实体重复此操作。

One approach that might help is to store the recordId in a new, separate entity. Create a new entity called something obvious like CKRecordInfo and keep the recordId there. Every other entity that has CloudKit info would have a one-to-one relationship to this entity. With this setup you'd fetch an instance of the new CKRecordInfo entity, and delete whichever object it's related to.

一种可能有用的方法是将recordId存储在一个新的独立实体中。创建一个名为CKRecordInfo的新实体,并将recordId保存在那里。具有CloudKit信息的每个其他实体都与该实体具有一对一的关系。通过此设置,您将获取新CKRecordInfo实体的实例,并删除与其相关的任何对象。

At the same time though-- I haven't used CloudKit, and it's more than a little surprising that it would give you just the recordId with no information about the record type. Getting the info from the notification would be ideal, if it's possible.

但同时 - 我还没有使用过CloudKit,而且它只会给你一个没有关于记录类型信息的recordId,这有点令人惊讶。如果可能的话,从通知中获取信息将是理想的。

#2


3  

Based on your clarification in the comments, I suggest configuring the .recordFields dictionary when you create the subscription. You can pass a limited amount of info in this dictionary, such as the record type. When you receive the deletion notification, you can unpack the recordFields from the notification object.

根据您在评论中的澄清,我建议您在创建订阅时配置.recordFields字典。您可以在此字典中传递有限的信息,例如记录类型。收到删除通知后,您可以从通知对象中解压缩recordFields。

You can find more info in Apple's docs at https://developer.apple.com/documentation/cloudkit/ckquerynotification/1428114-recordfields

您可以在Apple的文档中找到更多信息,网址为https://developer.apple.com/documentation/cloudkit/ckquerynotification/1428114-recordfields

Update

更新

Here's how I do it. I use objective-C, so you'll have to sort out the SWIFT syntax. But the steps are:

我就是这样做的。我使用objective-C,所以你必须整理SWIFT语法。但步骤是:

Create an array of records I want sent in the notif

创建我想在通知中发送的记录数组

Create a subscription

创建订阅

Create a notificationInfo object

创建notificationInfo对象

Add my desired keys array to the notificationInfo object

将我想要的键数组添加到notificationInfo对象

Create the sub using a CKModifySubscriptionsOperation

使用CKModifySubscriptionsOperation创建子

NSArray *desiredKeys = @[fieldname1, fieldname1, fieldname1];
CKQuerySubscription *subscription = [[CKQuerySubscription alloc] initWithRecordType:recordName
                                                                          predicate:searchConditions
                                                                     subscriptionID:subscriptionID
                                                                            options:fireOn];

CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
notificationInfo.shouldBadge = shouldBadge;
notificationInfo.desiredKeys = desiredKeys;

subscription.notificationInfo = notificationInfo;

CKModifySubscriptionsOperation *subOp = [[CKModifySubscriptionsOperation alloc] initWithSubscriptionsToSave:subsToCreate subscriptionIDsToDelete:subsToDelete];
subOp.modifySubscriptionsCompletionBlock = ^(NSArray<CKSubscription *> *savedSubscriptions,
                                             NSArray<NSString *> *deletedSubscriptionIDs,
                                             NSError *operationError)
{
   //do whatever
}

subOp.database = database;      //set to either public or private DB
[myQueue addOperation:subOp];

When you receive a notification, you just pull the objects back out of the notificationInfo:

收到通知后,只需将对象拉出notificationInfo:

    NSString *value1 = [queryNotification.recordFields objectForKey:fieldname1];

If it won't let you actually add the recordType, then you may have to create a custom field with some indicator of the record type, and then pass that as I described above, or fetch the record in question by using the recordID you received in the notification.

如果它不允许您实际添加recordType,那么您可能必须使用记录类型的某个指示符创建自定义字段,然后如上所述传递,或者使用您收到的recordID获取相关记录在通知中。


分享到: