37

我只是在想,因为如果我创建两个块然后将它们添加到 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 对象的非常罕见的示例之一,可以在堆栈上创建而无需钻研荒谬的技巧)。这意味着一旦此方法退出,您的数组现在指向垃圾,因为它指向的块不再存在。要正确执行此操作,您应该执行以下操作:

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 回答