iOS,CloudKit - 我的应用程序启动时是否需要进行提取? [英] iOS, CloudKit - do I need to do a fetch when my app starts?

查看:123
本文介绍了iOS,CloudKit - 我的应用程序启动时是否需要进行提取?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm setting up registrations for notifications of iCloud changes.

假设有一个新设备被添加到icloud帐户,我只是想知道该设备将如何获取私人数据库记录。

Say a new device is added to the icloud account, I'm just wondering how that device will get the private database records.

我是否需要进行一次性查询?

Do I need to do a one off query?

我希望该通知将在所有其他时间使用。

I'm hoping that notifications will be used at all other times.

推荐答案

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

Let's start with some relevant characteristics of subscription notifications:

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

First: Subscription Notifications are specific to a user + device pair. If I install you app on my phone, I start getting notifications. I won't get the notifications on another device until I install the app there, too.

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

Second: Notifications are unreliable. Apple docs are quite clear that they do not guarantee delivery. When you receive a notification, there could have been several prior notifications. Thus, Apple offer's two mechanisms to track which notifications you've seen:


  1. 读取/未读状态:您可以将通知标记为已读。 Apple的文档与实际上的内容相矛盾。 此页面

  1. Read/unread status: you can mark notifs as read. Apple's docs contradict themselves about what this actually does. This page says




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

If you mark one or more notifications as read using a CKMarkNotificationsReadOperation object, those notifications are not returned, even if you specify nil for previousServerChangeToken.

然而,事实并非如此。获取操作清楚地返回读取和未读通知。 WWDC 2014 Video 231(Advanced Cloudkit)与文档页面相矛盾,解释了总是返回未读令牌以及读取令牌,因此多个设备可以同步。该视频提供了一个显示此行为的好处的具体示例。此行为也记录在SO上: CKFetchNotificationChangesOperation返回旧通知

However, this isn't true. The fetch operation clearly returns both read and unread notifications. WWDC 2014 Video 231 (Advanced Cloudkit) contradicts the documentation page, explaining that unread tokens are always returned as well as read tokens so multiple devices can sync up. The video gives a specific example that shows the benefits of this behavior. This behavior is also documented on SO: CKFetchNotificationChangesOperation returning old notifications


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

  1. change token: each fetch operation will return a change token that you can cache. If you pass the token to a fetch, the fetch will only return tokens from that point, whether read or unread.

乍一看,似乎Apple正在提供您想要的行为:在一台设备上安装应用程序,开始处理通知,在第二台设备上安装应用程序,并获取所有这些先前的通知以便赶上。

At first glance, it would seem that Apple is providing for the behavior you want: install the app on one device, start processing notifications, install the app on a second device, and fetch all those prior notifications in order to catch up.

不幸的是,正如我在中所记录的那样CKFetchNotificationChangesOperation:为什么READ通知都是nil?,每当我获取通知时,之前标记为read的都会有nil内容。读取通知中的所有信息都将丢失。

Unfortunately, as I've documented in CKFetchNotificationChangesOperation: why are READ notifications all nil?, any time I fetch notifications, the ones previously marked as "read" all have nil contents. All the info in the read notifications is lost.

在我的方案中,我选择:

In my scenario, I chose to:


  1. 始终在启动时获取最新记录

  2. 使用以前保存的更改令牌获取通知(如果存在)

  3. 处理新通知

  4. 将通知标记为已读

  5. 保存最新的更改标记,以便在下次提取时使用

  1. Always fetch the latest record(s) at startup
  2. Fetch notifications using the previously saved change token (if it exists)
  3. Process the new notifications
  4. Mark the notifications as read
  5. save the latest change token for use on the next fetch

对于您的方案,您可以尝试:

For your scenario, you could try:


  1. 使用以前的方式获取通知保存的更改令牌(如果存在)

  2. 处理通知(不要将其标记为已读)

  3. 保存最新的更改令牌以供在next fetch

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

Your first device will ignore old notifications on each subsequent fetch because you're starting each fetch from the change token point. Your second device will start with a nil change token on the first execution, and thus pick up all of the old notifications.

提醒一句:尽管上述WWDC视频明确表示Apple保留了所有旧通知,但我没有找到任何文档说明他们持有这些信息的时间。它可能是永远的,也可能不是。

One word of caution: even though aforementioned WWDC video clearly says Apple keeps all the old notifications, I have found no documentation that says how long they hold this info. It may be forever, it may not.

使用通知获取示例更新

以下是我如何获取通知,标记它们以及缓存更改标记:

Here's how I'm fetching notifications, marking them read, and caching the change token:

@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];
}

要从用户默认值设置和检索缓存的更改令牌,我使用以下两个函数:

To set and retrieve the cached change token from the user defaults, I use the following two functions:

-(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];    
}

这篇关于iOS,CloudKit - 我的应用程序启动时是否需要进行提取?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆