さて、同期させるのに具体的な code ですが、こんな感じになりました:
+ (NSArray *) queryCategory
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create( 0 );
CKContainer* defaultContainer = [CKContainer defaultContainer];
CKDatabase* publicDatabase = [defaultContainer publicCloudDatabase];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"name != %@", @"nil"];
CKQuery* query = [[CKQuery alloc] initWithRecordType:@"Category" predicate:predicate];
__block NSArray* reArray = [NSArray new];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[publicDatabase performQuery:query
inZoneWithID:nil
completionHandler:^(NSArray* results, NSError* error)
{
if ( !error )
{
// NSLog(@"%@", results);
for ( CKRecord* item in results )
{
NSLog(@"%@, %@, %@, %@, %@", item[@"name"], item[@"modifiedAt"], item[@"createdBy"], item[(void)(@"changeTag"), item[@"recordName"]]);
}
reArray = [results copy];
NSLog( @"count of hoge = %ld", [reArray count]);
}
else
{
NSLog(@"error: %@", error);
}
dispatch_semaphore_signal( semaphore );
}];// end of publicDatabase
});
while( dispatch_semaphore_wait( semaphore, DISPATCH_TIME_NOW ))
{
// NSLog(@"run loop");
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1f]];
}
NSLog( @"loop out count of hoge = %ld", [reArray count] );
return reArray;
}
この method はユーティリティを集約した class に記載しました。この class に登録してある method は、どれも単体で使う用途が主で、今回の method も class method とした方が使うときに便利なのでそうしています。
semaphore 変数を定義し、CKQuery のための前準備を書きます。
戻り値として使用する array は、__block 宣言して、block の外でも使えるようにしておきます。
dispatch_async(dispatch_get_global_queue 部分が曲者で、同期させるのに非同期にするの?というのが、ぱっと見、珍妙に思えますが、こうします。
次に、performQuery で query を実行。
この method の中では、処理が完了したら dispatch_semaphore_signal を実行します。
その下の while 部分が肝要で、semapphore がクリアされるまで待たせます。
実際、この code を動かしてみると、サーバとやりとりしている都合、少し待たされる印象です。また、言わずもがなですが、アプリを起動している端末では iCloud にログインしていないとなりません。なので、実際にはこの method を実行する前に、その端末が iCloud にログインしているか確かめる処理が必要です。
という訳で、CloudKit で同期できるようになりましたが、果たしてこれが洗練された方法であるかは、さっぱりわかりません。