iOS,CloudKit-我的应用程序启动时需要进行获取



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

说添加了一个新设备添加到iCloud帐户中,我只是想知道该设备将如何获取私有数据库记录。

我需要做一个关闭查询吗?

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

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

首先:订阅通知特定于用户 设备对。如果我在手机上安装您的应用程序,我将开始收到通知。直到我也将应用程序安装到那里,我才会在其他设备上收到通知。

第二:通知不可靠。Apple文档很清楚,它们不能保证交货。当您收到通知时,可能已经有几次通知。因此,Apple提供的两种机制可以跟踪您看到的通知:

  1. 读取/未读状态:您可以将Notifs标记为读取。苹果的文档与实际的作用相矛盾。此页面说

如果使用ckmarknotificationReadoperation对象将一个或多个通知标记为读取,则这些通知也不会返回,即使您为先前的verchangetoken指定零。

但是,这不是真的。获取操作清楚地返回了读取和未读通知。WWDC 2014 Video 231(高级CloudKit)与文档页面相矛盾,解释了始终返回未读令牌以及读取令牌,因此可以同步多个设备。该视频给出了一个特定的示例,显示了这种行为的好处。此行为也记录在SO上:CKFetchNotificationChangeSoperation返回旧通知

  1. 更改令牌:每个获取操作将返回可以缓存的更改令牌。如果将令牌传递给获取,则获取只会从那时起返回令牌,无论是阅读还是未读。

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

不幸的是,正如我在ckfetchnotification ChangeSoperation中记录的那样:为什么读通知全部nil?读取通知中的所有信息都丢失了。

在我的情况下,我选择了:

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

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

  1. 使用先前保存的更改令牌获取通知(如果存在)
  2. 处理通知(请勿将其标记为读取)
  3. 保存最新的更改令牌,用于在下一个获取

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

一个谨慎的词:即使上述WWDC视频清楚地说苹果保留了所有旧的通知,但我没有发现任何文档,说明他们持有此信息多长时间。它可能是永远的,可能不是。

使用通知fetch示例

更新

这是我如何获取通知,标记它们阅读并缓存更改令牌:

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

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

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

相关内容

  • 没有找到相关文章

最新更新