在大量搜索示例代码后,管理好凑齐CKFetchRecordsOperation;这是......但我一定错过了什么。不要误会我的意思......但是......
要执行CKFetchRecordsOperation,您需要一个CKRecordIDs的NSArray;要获得CKRecordID的NSArray,你需要执行CKQuery,你可以构建你的CKRecordIDs的NSArray。
但是等一下,提取CKRecordIDs的过程使用CKQuery,我可以直接下载CKRecords吗?
如果不使用CKQuery,如何获得CKRecordID的NSArray?
-(void)doSingleBeaconsDownload
{
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:@"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
NSPredicate *predicatex = [NSPredicate predicateWithFormat:@"iBeaconConfig = %@",iBeaconsConfirmed.giReferenceID];
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Running" predicate:predicatex];
[self.delegate performSelectorOnMainThread:@selector(processCompleted:) withObject:@"Downloading Configuration ..." waitUntilDone:YES];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
if (error) {
NSLog(@"Batch Download Error iCloud error %@",error);
}
else {
NSMutableArray *rex2download = [[NSMutableArray alloc] init];
for (CKRecord *rex in results) {
[rex2download addObject:rex.recordID];
}
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:rex2download];
/* fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, CKRecordID *recordID, NSError *error) {
if (error) {
// Retain the record IDs for failed fetches
}
else {
// Do something with each record downloaded
}
};*/
fetchRecordsOperation.perRecordProgressBlock = ^(CKRecordID *record, double recordsDownloaded) {
if (error) {
// damn ...
} else {
NSLog(@"Downloaded %f", recordsDownloaded);
}
};
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
// Failed to fetch all or some of the records
}
else {
for(CKRecord *record in results) {
NSLog(@"Fini download %lu",(unsigned long)[recordsByRecordID count]);
}
[self.delegate performSelectorOnMainThread:@selector(beaconsDownloaded:) withObject:noOf waitUntilDone:YES];
}
};
[publicDatabase addOperation:fetchRecordsOperation];
}
}];
}
答案 0 :(得分:9)
来自Apple Documentation:CKFetchRecordsOperation对象从iCloud中检索CKRecord对象(您已知道的ID)。
CKQueryOperation用于根据某些查询从iCloud中检索CKRecords,因此即使您不知道他们的recordID,也可以获取它们。只有拥有CKRecordID时才使用CKFetchRecordsOperation。您可以在不访问iCloud的情况下创建CKRecordID,并且可以将它们存储在您拥有的任何本地存储中。
我用于此类操作的一个好用例是,当您想要修改CKRecord时,您需要先从iCloud中检索它(使用CKFetchRecordsOperation),然后使用CKModifyRecordsOperation将其保存回来。
查看CloudKit上的两个WWDC 2014视频,可以很好地解释这一点。
答案 1 :(得分:0)
感谢您的帮助!我设法在代码中创建了一个CKQueryOperation,但是......但是我的代码很快就会变得难以理解,还有更多这些嵌套循环?当然有一种更优雅的方式来链接CKQuery / Fetch / Modify操作;尝试过依赖但仍缺少某些东西?
-(void)doSingleBeaconsDownload
{
[self.delegate performSelectorOnMainThread:@selector(processCompleted:) withObject:@"Downloading Configuration ..." waitUntilDone:YES];
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:@"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
NSPredicate *predicatex = [NSPredicate predicateWithFormat:@"iBeaconConfig = %@",iBeaconsConfirmed.giReferenceID];
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Running" predicate:predicatex];
CKQueryOperation *queryOp =[[CKQueryOperation alloc] initWithQuery:query];
queryOp.desiredKeys = @[@"record.recordID.recordName"];
queryOp.resultsLimit = CKQueryOperationMaximumResults;
NSMutableArray *rex2download = [[NSMutableArray alloc] init];
queryOp.recordFetchedBlock = ^(CKRecord *results)
{
[rex2download addObject:results.recordID];
};
queryOp.queryCompletionBlock = ^(CKQueryCursor *cursor, NSError *error)
{
// Cursor it seems contains a reference to a second call to it [required] if you try download more then 100 records
if (error) {
NSLog(@"Batch Download Error iCloud error %@",error);
}
else {
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:rex2download];
fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, CKRecordID *recordID, NSError *error) {
if (error) {
// Retain the record IDs for failed fetches
}
else {
// Do something ..
}
};
fetchRecordsOperation.perRecordProgressBlock = ^(CKRecordID *record, double recordsDownloaded) {
if (error) {
// damn
} else {
NSLog(@"Downloaded X");
}
};
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
// Failed to fetch all or some of the records
}
else {
… Final clean up
}
};
[publicDatabase addOperation:fetchRecordsOperation];
}
};
[publicDatabase addOperation:queryOp];
}
答案 2 :(得分:0)
谢谢哈利;这是我的第三个也是最后一个解决方案;使用单例全局变量在两个CKQueryOperations之间传递数据;不知道这是最佳/良好的做法,但它有效
...似乎很可惜你不能使用这样的东西......
[fetchRecordsOperation addDependency:queryOp]; &
[queue fetchRecordsOperation]; (doesn't compile)
将是一个更清洁的解决方案......无论如何这里是完整性的V3 ..
-(void)doSingleBeaconsDownloadV3
{
NSLog(@"doQuery executing");
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:@"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
NSPredicate *predicatex = [NSPredicate predicateWithFormat:@"iBeaconConfig = %@",iBeaconsConfirmed.giReferenceID];
CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Running" predicate:predicatex];
CKQueryOperation *queryOp =[[CKQueryOperation alloc] initWithQuery:query];
queryOp.desiredKeys = @[@"record.recordID.recordName"];
queryOp.resultsLimit = CKQueryOperationMaximumResults;
//NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO];
//query.sortDescriptors = @[sortDescriptor];
queryOp.recordFetchedBlock = ^(CKRecord *results)
{
[iBeaconsConfirmed.giRex2Download addObject:results.recordID];
NSLog(@"fetched %lu",[iBeaconsConfirmed.giRex2Download count]);
};
queryOp.queryCompletionBlock = ^(CKQueryCursor *cursor, NSError *error)
{
if (error) {
NSLog(@"Batch Download Error iCloud error %@",error);
} else {
NSLog(@"fetched %lu",[iBeaconsConfirmed.giRex2Download count]);
[self DoFetchV2];
}
};
[publicDatabase addOperation:queryOp];
}
-(void)DoFetchV2
{
NSLog(@"dofetch executing %lu",[iBeaconsConfirmed.giRex2Download count]);
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:@"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:iBeaconsConfirmed.giRex2Download];
fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, CKRecordID *recordID, NSError *error) {
if (error) {
// Retain the record IDs for failed fetches
}
else {
// Do something useful with data
}
};
fetchRecordsOperation.perRecordProgressBlock = ^(CKRecordID *record, double recordsDownloaded)
{
NSLog(@"Downloaded X");
};
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
// Failed to fetch all or some of the records
} else {
NSLog(@"Fini download %lu",(unsigned long)[recordsByRecordID count]);
}
};
[publicDatabase addOperation:fetchRecordsOperation];
}