LoginSignup
27
22

More than 5 years have passed since last update.

Objective-CのBlocksとSwiftのクロージャでは変数のキャプチャが違う

Last updated at Posted at 2015-05-13

まず、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

27
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
22