Подтвердить что ты не робот

Выполнение блоков из NSArray?

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

Ответ 1

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

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

Ответ 3

Конечно, вы можете.

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