37

ブロックを2つ作成してNSArrayに追加すると、ブロックをオブジェクトのように扱うことができるので、配列から実行する方法はありますか?

int (^Block_001)(void) = ^{ return 101; };
int (^Block_002)(void) = ^{ return 202; };
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];

編集:明確にするために更新@davedelongの優れた回答ごと

int (^Block_001)(void) = [^{ return 101; } copy];
int (^Block_002)(void) = [^{ return 202; } copy];
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];

[Block_001 release];
[Block_002 release];
4

3 に答える 3

60

@KennyTM と @David は正しいですが、コードが間違っている可能性があります。理由は次のとおりです。

NSArraywith オブジェクトを作成するとretain、オブジェクトがその中に入れられます。ブロックの場合は、Block_retain関数を使用しています。これは、作成したブロックを配列が保持していることを意味しますが、それはスタック上に存在します(ブロックは、ばかげたトリックを掘り下げることなくスタック上に作成できる Objective-C オブジェクトの非常にまれな例の 1 つです)。つまり、このメソッドが終了するとすぐに、配列が指していたブロックが存在しなくなるため、配列はガベージを指すようになります。これを適切に行うには、次のことを行う必要があります。

int (^Block_001)(void) = [^{ return 101; } copy];
int (^Block_002)(void) = [^{ return 202; } copy];
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];

[Block_001 release];
[Block_002 release];

ブロックで呼び出すことによりcopy、ブロックをスタックからヒープに明示的に移動し、メソッド/関数が終了した後もブロックを安全に残すことができます。次に、ブロックを配列に追加した後、copy(NARC ルールのため) への後続の呼び出しとのバランスを取る必要がありますrelease。わかる?

于 2010-07-15T17:27:26.450 に答える
29

もちろん、()他のブロックと同じように で呼び出すだけですが、 から取得した値を型キャストする必要がありますNSArray。これが例です(typedefを追加しました。そうしないと頭が痛くなるためです):

typedef int (^IntBlock)(void);
IntBlock Block_001 = ^{ return 101; };
IntBlock Block_002 = ^{ return 202; };
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil];
int x = ((IntBlock)[array objectAtIndex:0]) (); // now x == 101
于 2010-07-15T17:08:29.257 に答える
7

もちろんできます。

int (^x)(void) = [array objectAtIndex:0];
printf("%d\n", x()); // prints 101.
于 2010-07-15T17:02:30.377 に答える