iphoneアプリ開発日記その3
Block とラムダとクロージャの間
ios の Blocks について調べてみた
ひとまず前買ってた本を読んでみる
…ああ、これラムダなのかな?
そういえば、どこかのサイトに Blocks = クロージャ みたいに書いてあった気がする。
クロージャについて調べてみよう
http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B8%E3%83%A3
どうやら、クロージャはラムダ式を使って実現しているとのこと。「ラムダ式 ⊃ Blocks」 って感じか
で、実行時でなく定義時の環境をコピーするんだとか
試してみた
ソース
int captured_value = 10; __block int block_value = 20; // Blocks 用の変数を宣言 void (^external_block)(int); void (^external_declared_block)(int); // 実体を代入 external_block = ^(int loop){ printf("external ~ loop: %d, captured: %d, block: %d\n", loop, captured_value, block_value); block_value ++; }; for (int loop_counter = 0; loop_counter < 3; loop_counter++){ external_block(loop_counter); external_declared_block = ^(int loop){ printf("external declared ~ loop: %d, captured: %d\n", loop, captured_value); }; external_declared_block(loop_counter); void (^internal_block)(int) = ^(int loop){ printf("internal ~ loop: %d, captured: %d, block: %d\n\n", loop, captured_value, block_value); }; internal_block(loop_counter); captured_value ++; } external_block(111); external_declared_block(111); //スコープ外なんで未定義のはず。やっちゃだめ
結果
external ~ loop: 0, captured: 10, block: 20 external declared ~ loop: 0, captured: 10 internal ~ loop: 0, captured: 10, block: 21 external ~ loop: 1, captured: 10, block: 21 external declared ~ loop: 1, captured: 11 internal ~ loop: 1, captured: 11, block: 22 external ~ loop: 2, captured: 10, block: 22 external declared ~ loop: 2, captured: 12 internal ~ loop: 2, captured: 12, block: 23 external ~ loop: 111, captured: 10, block: 23 external declared ~ loop: 111, captured: 12
ということで、宣言時の変数が保持されているのがわかる
__block ってやると、Blocks 内部で変数を弄れるようになる
注意点
Delegate の代わりに Blocks を使うのが流行ってるらしいのだが、
Blocks 内部でメンバ変数にアクセスすると、さっくり循環参照を起こすとか。
対応策はこんな感じのようだ
- 弱参照をつかう
- 解放処理をきっちり書く
いまいち完全に把握できてないので、もう少し調べる必要があるかなー