iOS,CloudKit – 当我的应用程序启动时,我需要做一个抓取吗?

我正在设置iCloud更改通知的注册。

说一个新的设备被添加到icloud帐户,我只是想知道该设备将如何获得私人数据库logging。

我需要做一个一个查询?

我希望通知会在其他时间使用。

我们从订阅通知的一些相关特征开始:

首先:订阅通知是特定于用户+设备对的。 如果我在手机上安装您的应用程序,我开始收到通知。 在我安装应用程序之前,我不会在其他设备上收到通知。

第二:通知是不可靠的。 苹果公司的文件很清楚,他们不保证交付。 当您收到通知时,可能会有几个事先通知。 因此,苹果提供了两种机制来跟踪您所看到的通知:

  1. 读取/未读状态:您可以将notifs标记为已读。 苹果公司的文件自相矛盾,这实际上是做什么的。 这个页面说

如果使用CKMarkNotificationsReadOperation对象将一个或多个通知标记为已读,则即使为previousServerChangeToken指定nil,也不会返回这些通知。

但是,这不是事实。 读取操作显然会返回已读和未读通知。 WWDC 2014 Video 231(Advanced Cloudkit)与文档页面相矛盾,解释了未读令牌总是返回以及读取令牌,因此多个设备可以同步。 该video给出了一个具体的例子,显示了这种行为的好处。 这种行为也logging在SO: CKFetchNotificationChangesOperation返回旧的通知

  1. 更改标记:每个获取操作都将返回一个可以caching的更改标记。 如果您将令牌传递给获取,则获取只会从该点返回令牌,无论是已读还是未读。

乍看之下,苹果公司似乎正在提供您想要的行为:在一台设备上安装应用程序,开始处理通知,在第二台设备上安装应用程序,并获取所有事先通知以赶上。

不幸的是,正如我在CKFetchNotificationChangesOperation中logging的:为什么READ通知全部为零? ,任何时候我提取通知,以前标记为“已读”的都没有内容。 读取通知中的所有信息都会丢失。

在我的情况下,我select了:

  1. 始终在启动时获取最新的logging
  2. 使用先前保存的更改令牌获取通知(如果存在)
  3. 处理新的通知
  4. 将通知标记为已读
  5. 保存最新的更改标记以供下次获取使用

对于你的情况,你可以尝试:

  1. 使用先前保存的更改令牌获取通知(如果存在)
  2. 处理通知(不要标记为已读)
  3. 保存最新的更改标记以供下次获取使用

您的第一个设备将忽略每个后续提取的旧通知,因为您正在从更改标记点开始每次提取。 您的第二个设备将在第一次执行时从零更改标记开始,从而提取所有旧通知。

谨慎的一句话:即使前面提到的WWDCvideo清楚地表明苹果保留了所有旧的通知,但是我没有find说明他们持有这个信息多久的文档。 它可能是永远的,也可能不是。

更新通知获取示例

以下是我如何获取通知,将其标记为已读,并caching更改标记:

@property CKServerChangeToken *notificationServerChangeToken; 

然后…

 -(void)checkForUnreadNotifications { //check for unread cloudkit messages CKFetchNotificationChangesOperation *op = [[CKFetchNotificationChangesOperation alloc] initWithPreviousServerChangeToken:_notificationServerChangeToken]; op.notificationChangedBlock = ^(CKNotification *notification) { //this fires for each received notification. Take action as needed. }; //maintain a pointer to the op. We will need to look at a property on the //op from within the completion block. Use __weak to prevent retain problems __weak CKFetchNotificationChangesOperation *operationLocal = op; op.fetchNotificationChangesCompletionBlock = ^(CKServerChangeToken *newServerChangeToken, NSError *opError) { //this fires once, at the end, after all notifications have been returned. //this is where I mark the notifications as read, for example. I've //omitted that step because it probably doesn't fit your scenario. //update the change token so we know where we left off [self setNotificationServerChangeToken:newServerChangeToken]; if (operationLocal.moreComing) { //more notifications are waiting, recursively keep reading [self checkForUnreadNotifications]; return; } }; [[CKContainer defaultContainer] addOperation:op]; } 

要从用户默认设置和检索caching的更改标记,我使用以下两个函数:

 -(void)setNotificationServerChangeToken:(CKServerChangeToken *)newServerChangeToken { //update the change token so we know where we left off _notificationServerChangeToken = newServerChangeToken; NSData *encodedServerChangeToken = [NSKeyedArchiver archivedDataWithRootObject:newServerChangeToken]; NSUserDefaults *userSettings = [NSUserDefaults standardUserDefaults]; [userSettings setObject:encodedServerChangeToken forKey:UD_KEY_NOTIFICATION_TOKEN_CKSERVERCHANGETOKEN_PROD]; //Note, the development and production cloudkit environments have separate change tokens. Depending on your needs, you may need to save both. } 

和…

 -(void)getNotificationServerChangeToken { NSUserDefaults *userSettings = [NSUserDefaults standardUserDefaults]; NSData *encodedServerChangeToken = [userSettings objectForKey:UD_KEY_NOTIFICATION_TOKEN_CKSERVERCHANGETOKEN_PROD]; _notificationServerChangeToken = [NSKeyedUnarchiver unarchiveObjectWithData:encodedServerChangeToken]; }