まず、Swiftで以下のコードを実行してみる。
var sampleStr = "ABCD"
let showCaptureString = {(number:Int) -> String in
sampleStr + String(number)
}
showCaptureString(99)
sampleStr = "DCBA"
showCaptureString(99)
まず、showCaptureStringというクロージャを定義。
これは受け取った数字とキャプチャしたsampleStrを連結して返すもの。
1行だけなのでreturnは省略できる。
実行結果は、最初のshowCaptureString(99)ではABCD99が返る。
そして、sampleStrをDCBAに書き換えた後、もう一度同じようにshowCaptureString(99)を実行すると、DCBA99が返る。
これと同じような事をObjective-CのBlocks構文を用いて実装してみる。
NSString *sampleStr = @"ABCD";
NSString *(^showCaptureString)(int) = ^(int number){
return [NSString stringWithFormat:@"%@%d",sampleStr,number];
};
NSLog(showCaptureString(99));
sampleStr = @"DCBA";
NSLog(showCaptureString(99));
最初のshowCaptureString(99)はABCD99が返る、これは自然。
しかし、sampleStrをDCBAに書き換えた後、showCaptureString(99)を実行しても同じようにABCD99という値が返る。
このような結果になる理由は、Objective-CのBlocksとSwiftのクロージャでは変数のキャプチャが異なるから。
Objective-Cでは一度キャプチャした値は後から変更されず、実行時にはキャプチャした時の値が使われる。
一方、Swiftではキャプチャした変数は実行時のものが使われる。
Objective-CでSwiftのクロージャのようにBlock内でキャプチャ変数を書き換えるには、__blockをつければ良い。
__block NSString *sampleStr = @"ABCD";
NSString *(^showCaptureString)(int) = ^(int number){
return [NSString stringWithFormat:@"%@%d",sampleStr,number];
};
NSLog(showCaptureString(99)); //ABCD99
sampleStr = @"DCBA";
NSLog(showCaptureString(99)); //DCBA99