Выполнение блоков из NSArray? - PullRequest
37 голосов
/ 15 июля 2010

Я просто подумал, как вы можете обращаться с блоками как с объектами, если я создам два из них и затем добавлю их в 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 ]

60 голосов
/ 15 июля 2010

@ 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. Имеет смысл?

29 голосов
/ 15 июля 2010

Конечно, вы просто вызываете его с (), как и любой другой блок, но вам нужно ввести значение, полученное из 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
7 голосов
/ 15 июля 2010

Конечно можно.

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