woshidan's loose leaf

ぼんやり勉強しています

ブロックを引数にして関数を書く素振り

ブロックはObjective-Cではなく、Mac OS X 10.6, iOS4 以降にC言語の機能として実装されたもの。

他の言語の機能でいうとクロージャ

試しに書いてみる

    // ブロックオブジェクトの定義
    // ^(引数列) { 本体 }
    // int型の引数を一つ取り、値を返さない関数へのポインタを格納する変数f
    void (*f)(int); // 変数名が真ん中にくるよ!!
    // int型の引数を一つ取り、値を返さないブロックへのポインタを格納する変数b
    void (^b)(int); // 関数とほぼ同じ形だけど名前の前には^がつくよ
    void (^b)(int) = ^(int i) { NSLog(@"integer %d", i); }; // ブロックオブジェクトの生成?
    b(1); // 実行
    
    void (^b2)(int i); // 宣言の時に仮引数書いてもいいよ

ブロックの外で定義された変数がキャプチャできる。

    int n = 8;
    void (^b)(int) = ^(int i) { NSLog(@"integer %d", i + n); };
    b(1); // integer 9
    n = 10;
    b(1); // integer 9 自動変数についてはブロックオブジェクト生成当時の値をキャプチャしているので、キャプチャ後にnが変更されてもbの結果は変わらない
    static int n = 8;
    void (^b)(int) = ^(int i) { NSLog(@"integer %d", i + n); };
    b(1); // integer 9
    n = 10;
    b(1); // integer 11 ローカル変数はキャプチャ以降も値が更新される
    // ブロックの中からローカル変数を変更することも可能

関数の引数にしたい

void (^b)(int) = ^(int i) { NSLog(@"integer %d", i); };
[self executeBlock:b withArgument:100];

- (void) executeBlock: (void (^)(int))block withArgument:(int)i {
    NSLog(@"execute block");
    block(i);
}
2017-08-28 20:29:38.539 Sunaba[70921:6280358] execute block
2017-08-28 20:29:38.539 Sunaba[70921:6280358] integer 100

あとJavaのComparableインタフェースみたいに一部のソート系メソッドで、ソートの基準を引数として受け取りたいとき、ブロックとして受け取らせる、みたいなことするみたいです。

詳解 Objective-C 2.0 改訂版

詳解 Objective-C 2.0 改訂版