はりまや日記

なんか適当にいろいろ綴ったりなんかするところ

iphoneアプリ開発日記その3

Block とラムダとクロージャの間

ios の Blocks について調べてみた


ひとまず前買ってた本を読んでみる

これー> 詳解 Objective-C 2.0 第3版


…ああ、これラムダなのかな?

そういえば、どこかのサイトに 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 内部でメンバ変数にアクセスすると、さっくり循環参照を起こすとか。

対応策はこんな感じのようだ

  • 弱参照をつかう
  • 解放処理をきっちり書く

いまいち完全に把握できてないので、もう少し調べる必要があるかなー