我的应用程序设置为接收 CloudKit 远程通知。有时它在后台运行时会收到这些通知。我还没有对这些通知做任何事情——我只是将 UIBackgroundFetchResultNewData 传递给了完成处理程序。原因是我不认为我可以在后台简单地从 CloudKit 下载 - 我认为只能通过 Background Fetch 或设置一个在后台运行的特殊作业来完成。但我现在正在重新审视这一点,我发现在 UIApplicationStateBackground 中运行 CKFetchRecordsOperation 并下载相关的 CKAsset 文件似乎确实有效。
所以我目前的代码是这样的:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
__ENTERING_METHOD__
CKNotification *ckNotification = [CKNotification notificationFromRemoteNotificationDictionary:userInfo];
if (ckNotification) {
if ([ckNotification.subscriptionID isEqualToString:kCKDocumentChangeSubscription]) {
CKRecordID *recordID = [(CKQueryNotification*)ckNotification recordID];
if (recordID) {
if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
if (completionHandler) {
completionHandler(UIBackgroundFetchResultNewData);
}
}
else {
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:@[recordID]];
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (completionHandler) {
completionHandler(UIBackgroundFetchResultFailed);
}
});
}
else {
CKRecord *ckDocumentRecord = recordsByRecordID[recordID];
CKAsset *documentAsset = [ckDocumentRecord objectForKey:ckDocumentAsset];
NSData *data = [NSData dataWithContentsOfURL:documentAsset.fileURL];
[self handleData:data];
UIBackgroundFetchResult result = (data == nil)?UIBackgroundFetchResultFailed:UIBackgroundFetchResultNewData;
if (completion) {
completion(result);
}
}
};
CKContainer *defaultContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [defaultContainer publicCloudDatabase];
[publicDatabase addOperation:fetchRecordsOperation];
}
}
else {
if (completionHandler) {
completionHandler(UIBackgroundFetchResultFailed);
}
}
}
else {
if (completionHandler) {
completionHandler(UIBackgroundFetchResultNoData);
}
}
}
else {
if (completionHandler) {
completionHandler(UIBackgroundFetchResultNoData);
}
}
}
我希望这段代码是这样的:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
__ENTERING_METHOD__
CKNotification *ckNotification = [CKNotification notificationFromRemoteNotificationDictionary:userInfo];
if (ckNotification) {
if ([ckNotification.subscriptionID isEqualToString:kCKDocumentChangeSubscription]) {
CKRecordID *recordID = [(CKQueryNotification*)ckNotification recordID];
if (recordID) {
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:@[recordID]];
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (completionHandler) {
completionHandler(UIBackgroundFetchResultFailed);
}
});
}
else {
CKRecord *ckDocumentRecord = recordsByRecordID[recordID];
CKAsset *documentAsset = [ckDocumentRecord objectForKey:ckDocumentAsset];
NSData *data = [NSData dataWithContentsOfURL:documentAsset.fileURL];
[self handleData:data];
UIBackgroundFetchResult result = (data == nil)?UIBackgroundFetchResultFailed:UIBackgroundFetchResultNewData;
if (completion) {
completion(result);
}
}
};
CKContainer *defaultContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [defaultContainer publicCloudDatabase];
[publicDatabase addOperation:fetchRecordsOperation];
}
else {
if (completionHandler) {
completionHandler(UIBackgroundFetchResultFailed);
}
}
}
else {
if (completionHandler) {
completionHandler(UIBackgroundFetchResultNoData);
}
}
}
else {
if (completionHandler) {
completionHandler(UIBackgroundFetchResultNoData);
}
}
}
在后台运行 CKFetchRecordsOperation 并下载相关的 CKAsset 文件是否构成违反可以(或应该)在后台执行的操作?