我的应用已设置为接收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文件是否违反了在后台可以(或应该)执行的操作?