blocksの落とし穴

blocksには数多くの落とし穴があります。
しかしそれを乗り越えることができれば、非常にスマートにかける状況はそれなりに増えると思います。

※注意：ここではARC環境での話です。一部MRCと状況が異なる場合があるかもしれません。

＜blocksはObjective-cのオブジェクトをstrong参照でキャプチャする＞
ここでいうキャプチャとは、ポインタをコピーしている、ということです。
なんで？と思われる方も多いと思います。しかし理由ははっきりしていています。
例えば、dispatch_afterで処理を遅延することを考えてみましょう。

```
        NSArray *sameArray = ...;
        
        int64_t delayInSeconds = 2.0;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            id obj = sameArray[2];
        });
```

ここでdispatch_afterに渡されたblocksは２秒後に遅延実行されます。
さて、sameArrayはARC管理オブジェクトですね。ということは、何もしなければ、2秒後には解放されてしまっているオブジェクトなんですね。しかし実際にはblocksがキャプチャ、つまりstrong参照を保持しているために、BAD_ACCESSにはならないんです。
blocksのキャプチャというのは非常に理にかなっているわけです。
さて、ここでさらに注意しなければならないことがあります。

＜blocksがキャプチャするのはObjective-cのオブジェクトだけ＞
例えばCGImageRefなんてどうでしょうか？　そう、もちろんキャプチャしません。
つまり、先ほどのように遅延実行で、CGImageRefは参照こそできるが、strongではもてないんです。ということは簡単にBAD_ACCESSがおこります。つまり、自分でCGImageRetainしないといけないんですね。これは本当に注意が必要です。

＜blocksの中でメンバ変数を使用すると、selfをstrongキャプチャする＞
これも恐ろしいです。仮にblocksをメンバにもつクラスがあり、そのblocksがselfをキャプチャすると、簡単に循環参照でメモリリークです。

```
@interface Hoge : NSObject
@property (nonatomic, copy) void (^blocks)();
@end
@implementation Hoge
{
    NSNumber *value;
}
- (id)init
{
    if(self = [super init])
    {
        value = @10;
        self.blocks = ^{
            [value description]; //循環参照！
        };
    }
    return self;
}
- (void)dealloc
{
    printf("dealloc");
}
@end
```

これをなんとかするには
__block __weak Hoge *_self = self;
などと一時変数としてweak参照の変数を使ったりすることで解決できますが、冗長でスマートではなく、私はあまり好きではありません。

＜blocksの寿命は記述したスコープのみ＞
厳密にはblocksによってはスタック領域に確保されるのではないblocksもあるのですが、
このように考えていた方が統一的で安全です。

```
        void (^blocks)();
        
        {
            blocks = ^{};//寿命はこのスコープのみ！
        }
        
        //ここでは既に死んでいる
        blocks();
```

このようなことをする場合は次のようにするのを推奨します

```
        void (^blocks)();
        
        {
            blocks = [^{} copy];//スタックからヒープに移動
        }
        
        //ここではヒープにあるblocksを参照、またARCで自動破棄
        blocks();
```

copyすると、blocksはスタックメモリからヒープメモリへと移動できるので、安全に後から呼べるのです。
関数の戻り値としてblocksを返す場合（関数言語でいうところの高階関数）も同様に、
copyしておくことを推奨します。
また、クラスプロパティもcopy属性推奨です。

つまり、「スコープを出た後でも呼び出したいblocksはコピーする」というのが安全の指標となるでしょう。dispatch_afterなんかは、内部で受けとったblocksをコピーしているので、呼び出し側では特に気にせずつかえるのです。

＜blocksはObjective-cオブジェクトである＞
先の例からも分かる通りです。しかしまあARC下では参照が自然と消滅するため、それほど意識しなくても良いかもしれません（循環参照以外では）。

＜blocksはキャプチャした変数をconst コピーする＞

```
        int a = 0;
        void (^blocks)() = ^{
            a = 3; //constなコピーなのでだめ！
        };
```

こういう場合に__blockを使います

```
        __block int a = 0;
        void (^blocks)() = ^{
            a = 3; //ok!
        };
```

また、次のような使い方すら可能です。

```
typedef int (^Hoge)();
Hoge function()
{
    __block int n = 10;
    return [^{
        return n--;
    } copy];
}

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        Hoge hoge = function();
        
        for(int i = 0 ; i < 5 ; ++i)
        {
            printf("%d, ", hoge()); //10, 9, 8, 7, 6, 
        }
    }
    return 0;
}

```

__blockの変数はcopyされるとスタックからヒープに本体と一緒に移動できるんです。

じゃあ次の例ではどうでしょうか？

```
typedef int (^Hoge)();
Hoge function()
{
    __block int n = 10;
    return [^{
        return n--;
    } copy];
}

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        Hoge hoge1 = function();
        Hoge hoge2 = [hoge1 copy];
        
        for(int i = 0 ; i < 5 ; ++i)
        {
            printf("%d, ", hoge1());
        }
        
        for(int i = 0 ; i < 5 ; ++i)
        {
            printf("%d, ", hoge2());
        }
　　//10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 
    }
    return 0;
}
```

そう、__blockのついた変数はコピーしても共有されるんですね。面白いです。

ここまで読むと、blocksは主に循環参照で非常に欠陥が多く、弱点もおおいのです。
それも仕方の無いことで、ガベージコレクションのあるC#などは非常にうまく言語に匿名関数がなじんでいます。ネイティブ言語の宿命といえばそうなのかもしれませんね。

しかしながら
・コールバックとして
・visitorパターンの代用として
・strategyパターンの代用として
・関数型プログラミングとして
等非常に強力な場面も多いです。注意深く使っていきたいですね。