CloudKit: 同期するにはどうするか(2)

さて、同期させるのに具体的な 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 で同期できるようになりましたが、果たしてこれが洗練された方法であるかは、さっぱりわかりません。