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 さんが下さったリプライを参考に__つか、まんま真似だわけですが__解決しました。
@uma_blue http://t.co/g1Xbw8AokL こんな感じの事がしたいということですか?
— りず (r.izumita) (@rizumita) April 11, 2013
参考にさせて頂いたのは、こちら。
プロパティなりインスタンス変数なりにフラグを用意して、それが切り替わるまで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 内でフラグの書き換えが行われるまで、ひたすら同じ処理を回すカタチなので、軽めの処理ならともかく負荷の大きい処理だったりすると、ちょっと困ります。
ちなみに、以下の様なアドバイスも頂いているので、これらでも書いてみて、もっとスマートに出来るようにしたいと考えています。
@uma_blue それGCDじゃ
— itok@いとーけー (@itok_twit) April 11, 2013
@uma_blue 普通にNSBlockOperation使えば良いじゃない。
— もっさりさん (@TeamMOSA2) April 11, 2013
@uma_blue あとは http://t.co/FqRDpC2Rmo こんな方法もあります。
— りず (r.izumita) (@rizumita) April 11, 2013
ちなみに、NSBlockOperation やGCD のdispatch_group は、結局Blocks の内部が非同期に処理されてしまい、望んだ挙動を取らせることができませんでした。
おそらく、私の書き方にどこか問題があったものと思われます。
勉強しろ、私。
Evernote for Developers 日本語 にもお世話になりました
あと、今回のEvernote SDK for iOS の変更内容とか、色々とお世話になったのがこちら。
日本語で質問とか投稿できます。
すばらしい。
せかっくオープンしたのに閑散としているんで、皆さんもっと利用しましょう。
私のこっ恥ずかしい質問が下に流れて行ってくれる様に。
脚注
↩01 | 本当にざっくりだな、おい。 |
---|