Evernote SDK for iOS ver.1.1.x のBlocks を同期的に扱う

投稿者: | 2013/04/12

Ver.1.1.x でごろっと変わりましたねEvernote SDK for iOS

GitHub で公開されているEvernote SDK for iOS ですが、先日のVer.1.1.x への更新から、内容がごろっと変わりました。

細かい内容はSDK References を見ていただくとして、ざっくり説明すると「ほとんどBlocks になっちゃった」です。 *01本当にざっくりだな、おい。

で、これまでのSDKでは通っていた書き方が通らなくなっていたりして、へっぽこな私は随分と泣かされました。

さんざん右往左往した挙句、奇特かつ素晴らしい周囲の方々のお陰で、なんとかなったので備忘録を兼ねて書いておきます。
つか、たぶん書かないと忘れちゃう。

 

Blocks の処理は基本的に非同期

何かと便利なBlocks ですが、処理は基本的に非同期みたいです。
まあ、よく理解でいていません。

とりあえず、これまで大丈夫だった以下の様なコードは、エラーも返してくれずに固まりました。

    EvernoteSession* eSession = [EvernoteSession sharedSession];
    NSString* aToken = [eSession authenticationToken];
    EDAMNoteStoreClient* ensClient = [eSession noteStore];
    EDAMNotebook* defaultNotebook = [ensClient getDefaultNotebook:aToken];
    NSLog(@"Default Notebook is %@", [defaultNotebook name]);

 

確認してみたところ、EDAMNoteStoreClient の取得段階で詰まっているみたいでした。

で、新SDKに従ってBlocks で書くと、ちゃんと動く。

    [[EvernoteNoteStore noteStore] getDefaultNotebookWithSuccess:^(EDAMNotebook *notebook) {
        NSLog(@"Default Notebook is %@", [notebook name]);
    } failure:^(NSError *error) {
        NSLog(@"ERROR: %@", [error description]);
    }];

 

素晴らしい。
すげー短く書ける。
セッションやら認証トークンやらいちいち用意しなくていい。

ただこれ、先にも言いましたけれど、非同期なんですよね。
Blocks の中であれこれする分には何の問題もないんですが、同じ関数内で取得したノートブックをどうこうしようとすると、非同期なんで「まだ取得できてねーよ」ということで、null が返って来ちゃいます。

    __block EDAMNotebook* defaultNotebook;
    [[EvernoteNoteStore noteStore] getDefaultNotebookWithSuccess:^(EDAMNotebook *notebook) {
		defaultNotebook = notebook;
        NSLog(@"Default Notebook is %@ in Blocks", [defaultNotebook name]);
    } failure:^(NSError *error) {
        NSLog(@"ERROR: %@", [error description]);
    }];
    NSLog(@"Default Notebook is %@", [defaultNotebook name]); // (null)

 

NSRunLoop で結果が帰ってくるまで回しとく

そんなわけで、どうしたものかと詰まっていたのですが、Twitter で@rizmita さんが下さったリプライを参考に__つか、まんま真似だわけですが__解決しました。


 

参考にさせて頂いたのは、こちら。

Cocoaの日々: [iOS] 非同期処理を同期処理に変える


プロパティなりインスタンス変数なりにフラグを用意して、それが切り替わるまでwhileを回して待機させるという方法です。

実は以前にもこの記事はみかけておりました。
ただ、その時はNSRunLoop を使う意味を理解しておらず、延々とwhile を回し続けてしまっていたんですよね。
お恥ずかしい。///

で、書いたコードはこんな感じ。

    __block EDAMNotebook* defaultNotebook;
    __block BOOL flg = NO;
    while ( flg == NO ) {
        [[EvernoteNoteStore noteStore] getDefaultNotebookWithSuccess:^(EDAMNotebook *notebook) {
            defaultNotebook = notebook;
            NSLog(@"Default Notebook is %@ in Blocks", [defaultNotebook name]);
            flg = YES;
        } failure:^(NSError *error) {
            NSLog(@"ERROR: %@", [error description]);
        }];
        
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
    }
    NSLog(@"Default Notebook is %@", [defaultNotebook name]);

これで何とか望む結果を得られました。

 

もーちょっとどうにかしたい

望む結果が得られたんだから、万々歳じゃねぇかよとも思うのですが、もうちょっとどうにかしたいです。

Blocks 内でフラグの書き換えが行われるまで、ひたすら同じ処理を回すカタチなので、軽めの処理ならともかく負荷の大きい処理だったりすると、ちょっと困ります。

ちなみに、以下の様なアドバイスも頂いているので、これらでも書いてみて、もっとスマートに出来るようにしたいと考えています。

ちなみに、NSBlockOperation やGCD のdispatch_group は、結局Blocks の内部が非同期に処理されてしまい、望んだ挙動を取らせることができませんでした。
おそらく、私の書き方にどこか問題があったものと思われます。

勉強しろ、私。

 

Evernote for Developers 日本語 にもお世話になりました

あと、今回のEvernote SDK for iOS の変更内容とか、色々とお世話になったのがこちら。

Evernote for Developers 日本語 – Evernote User Forum


日本語で質問とか投稿できます。
すばらしい。

せかっくオープンしたのに閑散としているんで、皆さんもっと利用しましょう。
私のこっ恥ずかしい質問が下に流れて行ってくれる様に。

 



 

脚注

脚注
01 本当にざっくりだな、おい。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください