Хранение блоков в массиве - PullRequest
50 голосов
/ 03 ноября 2011

В Objective-C я знаю, что блоки считаются объектами, поэтому мне было интересно, можно ли их хранить в массиве.Возникает вопрос, являются ли блоки первоклассными объектами или они просто обрабатываются как объекты ради передачи их между объектами?Если они являются объектами первого класса, то не должны ли они храниться в массивах?

Ответы [ 2 ]

90 голосов
/ 03 ноября 2011

РЕДАКТИРОВАТЬ: не вдаваясь в подробности, теперь в ARC вы можете добавлять блоки в коллекции, как и любой другой объект (см. Обсуждение).

Я оставил исходный ответ без изменений, поскольку он содержит некоторые интересные технические детали.


Возникает вопрос, являются ли блоки первоклассными объектами или они просто относиться как к объектам ради передачи их между объекты? Если они являются объектами первого класса, то не должны ли они быть хранится в массивах?

Блоки - это объекты Objective-C, которые очень похожи на любой другой объект NSO, с парой ключевых отличий:

  • Блоки всегда генерируются компилятором. Они фактически «alloc / init» редактируются во время выполнения, поскольку выполнение проходит через объявление блоков.

  • Блоки изначально создаются в стеке. Block_copy () или copy метод должен использоваться для перемещения блока в кучу, если блок должен пережить текущую область (см. Точку ARC ниже).

  • У блоков на самом деле нет вызываемого API, кроме управления памятью.

  • Чтобы поместить блок в коллекцию, его сначала нужно скопировать . Всегда. В том числе по ARC. (см. Комментарии.) Если вы этого не сделаете, есть риск, что выделенный стеку блок будет autoreleased, и ваше приложение позже будет аварийно завершено.

  • Копирование блока на основе стека копирует также все захваченное состояние. Если вы делаете несколько копий блока, более эффективно скопировать его один раз, а затем скопировать копию (потому что копирование копии просто увеличивает количество сохраняемых элементов, поскольку блоки являются неизменяемыми).

  • В ARC возврат блока из метода или функции "просто работает"; оно будет автоматически скопировано в кучу, и возвращение будет автоматически освобожденным блоком (компилятор может оптимизировать автоматическое освобождение при определенных обстоятельствах). Даже с ARC вам все равно нужно скопировать блок, прежде чем вставить его в коллекцию.

Я написал пару постов в блоге, в которых содержится введение в блоки и некоторые советы и рекомендации . Вы можете найти их интересными.

И, да, добавление их в словари весьма полезно. Я написал пару кусочков кода, где я помещал блоки в словари как обработчики команд, где ключом было имя команды. Очень удобно.

39 голосов
/ 03 ноября 2011

Да, блоки на самом деле являются объектами, и вы можете поместить их в массивы:

NSMutableArray *arr = [NSMutableArray new];
[arr addObject:^(){NSLog(@"my block");}];
void (^ myblock)() = [arr objectAtIndex:0];
myblock();

, это поместит «мой блок» в консоль.

...