如何从来自 fetchAllSubscriptionsWithCompletionHandler 的 CKSubscriptionID 中检索 CKRecord?
Posted
技术标签:
【中文标题】如何从来自 fetchAllSubscriptionsWithCompletionHandler 的 CKSubscriptionID 中检索 CKRecord?【英文标题】:How to Retrieve the CKRecord from the CKSubscriptionID that came from fetchAllSubscriptionsWithCompletionHandler? 【发布时间】:2017-07-11 14:17:31 【问题描述】:感谢您的建议!
我正在使用 fetchAllSubscriptionsWithCompletionHandler,并且在发送推送通知后,我确实看到了每个 CKSubscription 的订阅 ID。如何从订阅 ID 中检索 CKRecord?
我没有看到来自已创建 CKReference 的远程推送通知。我可以通过 CloudKit DashBoard 查看 CKRecord 及其相关记录。我确实会在创建父记录时收到推送通知,但不会在子记录上创建 CKReference 时收到。
-(void)SubscribeForReference:(CKRecord *)record
NSUserDefaults *trackSubscription = [NSUserDefaults standardUserDefaults];
BOOL hasSubscribed = [[NSUserDefaults standardUserDefaults] objectForKey:@"alreadySubscribedForReference"] != nil;
//BOOL hasSubscribed = [trackSubscription objectForKey:@"alreadySubscribedForReference"];
if (hasSubscribed == false)
//creates a subscription based on a CKReference between two ckrecords
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"sentences == %@", record.recordID];
// 1) subscribe to record creations
CKSubscription *subscriptionRelation =
[[CKSubscription alloc] initWithRecordType:@"RecordTypeName"
predicate:predicate
options:CKSubscriptionOptionsFiresOnRecordCreation | CKSubscriptionOptionsFiresOnRecordUpdate | CKSubscriptionOptionsFiresOnRecordDeletion | CKSubscriptionOptionsFiresOnRecordUpdate];
//http://***.com/questions/27371588/cloudkit-notifications
CKNotificationInfo *notificationInfo = [[CKNotificationInfo alloc] init];
// I added this because of apple's documentation
notificationInfo.desiredKeys = @[@"word",@"identifier"];
notificationInfo.alertLocalizationArgs = @[@"word"];
notificationInfo.alertLocalizationKey = @"%1$@";
notificationInfo.shouldBadge = YES;
subscriptionRelation.notificationInfo = notificationInfo;
[self.privateDatabase saveSubscription:subscriptionRelation completionHandler:^(CKSubscription * _Nullable subscription, NSError * _Nullable error)
if (error == nil)
[trackSubscription setObject:subscription.subscriptionID forKey:@"alreadySubscribedForReference"];
[trackSubscription synchronize];
else
NSLog(@"something went wrong with saving the CKSubcription with error...\n%@\n",[error localizedDescription]);
];
else
NSLog(@"\nSubscribeForReference: ALREADY has subscription: %@ set for key 'alreadySubscribedForReference' \n\n ", [trackSubscription objectForKey:@"alreadySubscribedForReference"]);
下面的代码在应用启动时运行,前提是有互联网连接:
-(void)runWhenAppStarts
CKFetchSubscriptionsOperation *fetchSubscriptionsOperation = [CKFetchSubscriptionsOperation fetchAllSubscriptionsOperation];
fetchSubscriptionsOperation.fetchSubscriptionCompletionBlock = ^(NSDictionary *subscriptionsBySubscriptionID, NSError *operationError)
if (operationError != nil)
// error in fetching our subscription
CloudKitErrorLog(__LINE__, NSStringFromSelector(_cmd), operationError);
if (operationError.code == CKErrorNotAuthenticated)
// try again after 3 seconds if we don't have a retry hint
//
NSNumber *retryAfter = operationError.userInfo[CKErrorRetryAfterKey] ? : @3;
NSLog(@"Error: %@. Recoverable, retry after %@ seconds", [operationError description], retryAfter);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(retryAfter.intValue * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
[self subscribe];
);
else
if (self.subscribed == NO)
// our user defaults says we haven't subscribed yet
//
if (subscriptionsBySubscriptionID != nil && subscriptionsBySubscriptionID.count > 0)
// we already have our one CKSubscription registered with the server that we didn't know about
// (not kept track in our NSUserDefaults) from a past app install perhaps,
//
NSLog(@"\nsubscriptionsBySubscriptionID (dictionary) = %@\n",subscriptionsBySubscriptionID);
NSArray *allSubscriptionIDKeys = [subscriptionsBySubscriptionID allKeys];
NSLog(@"\nallSubscriptionIDKeys (array) = %@\n",allSubscriptionIDKeys);
if (allSubscriptionIDKeys != nil)
[self updateUserDefaults:allSubscriptionIDKeys[0]];
for (NSString *subscriptions in allSubscriptionIDKeys)
NSLog(@"subscriptionID: %@\n",subscriptions);
else
// no subscriptions found on the server, so subscribe
NSLog(@"...starting subscriptions on server...\n");
[self startSubscriptions];
else
// our user defaults says we have already subscribed, so check if the subscription ID matches ours
//
NSLog(@"...our user defaults says we have already subscribed, with subscriptionsBySubscriptionID = %@\nso check if the subscription ID matches the one already stored in NSUserDefaults...\n",subscriptionsBySubscriptionID);
if (subscriptionsBySubscriptionID != nil && subscriptionsBySubscriptionID.count > 0)
// we already have our one CKSubscription registered with the server that
// we didn't know about (not kept track in our NSUserDefaults) from a past app install perhaps,
//
//NSDictionary *subscriptionsBySubscriptionID has a structure of @key: value == @NSString: CKSubscription
NSArray *allSubscriptionIDKeys = [subscriptionsBySubscriptionID allKeys];//contains the NSString representation of the subscriptionID.
NSArray *allSubscriptionIDVALUES = [subscriptionsBySubscriptionID allValues];// the values are the corresponding CKSubscription objects
for (CKSubscription *values in allSubscriptionIDVALUES)
NSLog(@"\nCKSubscriptionValue = %@\n",values);
NSLog(@"\n...we already have our one CKSubscription registered with the server that..so lets look at allSubscriptionIDKeys =%@.\n\nvalues ...\nallSubscriptionIDVALUES = %@\n\n",allSubscriptionIDKeys,allSubscriptionIDVALUES);
if (allSubscriptionIDKeys != nil)
NSString *ourSubscriptionID = [[NSUserDefaults standardUserDefaults] objectForKey:kSubscriptionIDKey];
if (![allSubscriptionIDKeys[0] isEqualToString:ourSubscriptionID])
// our subscription ID doesn't match what is on the server, to update our to match
NSLog(@"...our subscription ID doesn't match what is on the server, going to update our NSUserDefaults...\n");
[self updateUserDefaults:allSubscriptionIDKeys[0]];
else
// they match, no more work here
NSLog(@"...iCloud server already has this subscriptionID, so do nothing.i.e. don't subscribe again..\n");
;
[self.privateDatabase addOperation:fetchSubscriptionsOperation];
【问题讨论】:
【参考方案1】:当您获取订阅时,您不会获得特定的记录 ID。相反,订阅的.recordType
会告诉您此订阅监控的记录的类型。通常,如果您有 1,000 个用户,那么您将拥有 1,000 个记录实例,并且每个用户都会创建 subs 来监控他们的实例何时被修改。
当订阅被触发时,您会收到通知。您可以使用CKFetchNotificationChangesOperation
来检索通知。每个通知都包含一个.recordID
值,该值具体告诉您哪些记录发生了更改并导致订阅触发。
您当前正在查询订阅者以确保用户已正确订阅。接下来,您还需要使用CKFetchNotificationChangesOperation
查询通知,以查看在订阅触发时更新了哪些记录。
【讨论】:
感谢您的回复! CKFetchSubscriptionsOperation *fetchSubscriptionsOperation 来自 Apple 的 CloudPhoto 示例代码。它检索存储在 iCloud 上的未读 cksubscription id。我的问题是现在我有那些订阅 ID,如何获取导致推送通知的 CKRecord?例如,我向 iCloud 添加了 5 条记录,但只看到 1 次推送通知。如何从导致推送通知的其他 4-CKRecord 中检索 CKRecord? 下面是我在检索 iCloud 上的订阅后看到的内容......我们已经在服务器上注册了一个 CKSubscription ......所以让我们看看 allSubscriptionIDKeys =( "AB3A1141 -B86C-445E-8B4C-06142F2717C9" , “98D91BCB-4D01-429F-90FB-D26C91993348”, “54FF397E-373D-4289-B6C0-D553BF104CD1”, “A07AC98F-AFCF-48D6-8DA1-A4F986B6E246”,“3E283535-8BAA -4BD2-8C8C-5E83F5274632”、“F35ADFBE-FEEA-4531-9BF3-D76F70F4E87A”、“CFD160D3-EB99-4933-965A-2EF5C1C68798”、“F1C7DA0C-7DBA-4D4C-BB0A-34AD180FD410”) Fetched CKSubscription 字典值 ... allSubscriptionIDVALUES = ( ".recordID
属性中获取触发通知的记录ID。您使用 CKFetchNotificationChangesOperation
获取通知【参考方案2】:
您可以从订阅谓词中提取 RecordID。
例如 - 如果订阅谓词是:
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"(author == %@)", artistRecordID];
artistRecordID 是对另一个记录类型的引用 - 那么您可以通过以下方式提取 RecordID:
[publicDatabase fetchAllSubscriptionsWithCompletionHandler:^(NSArray<CKSubscription *> *subscriptions, NSError *error)
if(error)
// handle error
else
[subscriptions indexOfObjectPassingTest:^BOOL(CKSubscription * obj, NSUInteger idx, BOOL *stop)
if ([obj.predicate isKindOfClass:[NSComparisonPredicate class]])
NSComparisonPredicate *p2a = (NSComparisonPredicate *)obj.predicate;
NSExpression *e6 = p2a.rightExpression;
CKReference* ref=e6.constantValue;
// you may extract RecordID here from ref
// for example - to compare against another RecordID:
if([ref.recordID.recordName isEqualToString:artistRecordID.recordID.recordName])
*stop=YES;
return YES;
return NO;
];
];
【讨论】:
以上是关于如何从来自 fetchAllSubscriptionsWithCompletionHandler 的 CKSubscriptionID 中检索 CKRecord?的主要内容,如果未能解决你的问题,请参考以下文章
JRBeanCollectionDataSource:如何从 JavaBean 显示来自 java.util.List 的数据?