2010-01-19

Objective-CでBlocks

いまさらながらObjective-CでBlocksってみたが、これはおもしろい。

まずは無名関数を使用。もともとgccには入れ子関数があったけど、必要な場所で定義できるのはすごく便利:

void foo(NSArray *array)
{
    ^(id x){ NSLog(@"%@", x); }(array);
}

クロージャなので、こういう風にも書ける:

void foo(NSArray *array)
{
    ^(){ NSLog(@"%@", array); }();
}

無名関数は引数にできる。って、これができなきゃ無名関数の意味がない:

void bar(void (^f)(id), id x)
{
    f(x);
}

void foo(NSArray *array)
{
    bar(^(id x){ NSLog(@"%@", x); }, array);
}

もちろん、クロージャも引数になる:

void bar(void (^f)())
{
    f();
}

void foo(NSArray *array)
{
    bar(^(){ NSLog(@"%@", array); });
}

無名関数は戻り値にもなる:

void (^bar())(id)
{
    return ^(id x){ NSLog(@"%@", x); };
}

void foo(NSArray *array)
{
    bar()(array);
}

しかし、クロージャを戻り値にするとコンパイル時にエラーになる:

void (^bar(id x))()
{
    return ^(){ NSLog(@"%@", x); };
}

void foo(NSArray *array)
{
    bar(array)();
}

元はC言語なんで、このへんが限界か。 と思ったが、 Block_copy() で環境を保存できるらしい:

#import <Block.h>

void (^bar(id x))()
{
    return Block_copy(^(){ NSLog(@"%@", x);});
}

void foo(NSArray *array)
{
    void (^f)() = bar(array);
    f();
    Block_release(f);
}

でも、なんか美しくないなぁ。無名なのが利点の一つなのに、名前をつけなきゃいけないなんて…

[00:10 | ]