从NSArray执行块?

时间:2010-07-15 16:54:35

标签: iphone objective-c cocoa-touch nsarray objective-c-blocks

我只是想,因为如果我创建其中两个然后将它们添加到NSArray中,你可以将块视为对象吗?有没有办法从数组中执行它们?

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

编辑:为了清晰而更新Per @ 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];

3 个答案:

答案 0 :(得分:60)

@KennyTM和@David是正确的,但您的代码可能有误。原因如下:

使用对象创建NSArray时,会retain放入对象。在块的情况下,它使用Block_retain函数。这意味着数组保留了您创建的块,但是生成在堆栈上的 (块是可以在堆栈上创建的Objective-C对象的非常罕见的示例之一,而无需深入研究荒谬的技巧)。这意味着只要此方法退出,您的数组现在就指向垃圾,因为它指向的块不再存在。要做到这一点,你应该这样做:

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。有意义吗?

答案 1 :(得分: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

答案 2 :(得分:7)

当然可以。

int (^x)(void) = [array objectAtIndex:0];
printf("%d\n", x()); // prints 101.