ошибка означает, что вы возвращаете значение, которое будет недействительным после возвращения метода. Это не только проблема с блоками, рассмотреть следующие вопросы:
- (int *) badMethod
{
int aLocalIntVariable;
return &aLocalIntVariable; // return a reference to aLocalIntVariable, but that variable is about to die...
}
Локальные переменные создаются, когда метод ввода, то место, где они живут, называется «стек». Когда метод возвращает эти локальные переменные, они уничтожаются. Вы можете вернуть значение в такую переменную, но вы не можете вернуть ссылку самой переменной - она будет недействительной. Вы можете передать ссылку на локальную переменную на метод, который вы вызываете, поскольку ваша локальная переменная все еще существует в этом случае.
В вашем случае вы создали блок. Objective-C выполняет создание значений блоков в стеке, то есть эффективно в анонимной локальной переменной и ссылается на них с использованием ссылки. Вы можете передать такую ссылку на метод, который вы вызываете, но вы не можете его вернуть - анонимная локальная переменная будет уничтожена так же, как и любая другая.
Однако Objective-C предоставляет вам два способа создания копии значения блока как объекта, который живет на «куче» и который переживет его создателя. Во-первых есть Block_copy
, который является функцией:
<reference to heap allocated block> = Block_copy(<reference to stack allocated block>);
Это оригинальный способ сделать это и поддерживается каждый - в том числе и в чистом коде C, блоки являются частью C, а не только Objective-C. Второй способ притворяется блока является объектом уже и позволяет передавать стандартное copy
сообщения:
<reference to heap allocated block> = [<reference to stack allocated block> copy];
Если вы в первую очередь Objective-C люди этого второй метод, вероятно, чувствует себя более комфортно, но размывает вопрос о том, почему это необходимо в первую очередь.
ARC помогает здесь, в автоматизации управления памятью, он автоматически копирует блоки из стека в кучу (по крайней мере, в современных компиляторах, он может не работать должным образом в предыдущих компиляторах), и поэтому программист может игнорировать то, что на самом деле является реализацией подробно.
Добавление: ARC
Последний абзац выше был запрошен @newacct и длинный Q & Комментарий обмена привели. В попытке сделать информацию в этом легче следовать, мы оба удалили наши комментарии, и я обобщил эту информацию здесь как добавление.
В понимании того, как ARC обрабатывает блоки двух документов полезны:
- Objective-C Automatic Reference Counting, в частности, разделы 3 (блоки указателей объектов сохран), 3.2.3 (типы объектов могущий быть удержанным действуют через обратные границы) и 7.5 (правила для копирования блоков).
- Transitioning to ARC Release Notes, в частности пункт часто задаваемых вопросов «Как блоки работают в ARC?»
Из них можно определить, что большую часть времени ARC будет обрабатывать все копирование блоков из стека до кучи в рамках управления всех типов объектов.
Вторая ссылка выделяет один случай, который по крайней мере на момент написания документа не обрабатывался автоматически. В этом случае блок, выделенный стеком, передается параметру метода типа id
, например. что-то вроде:
- (void) takeBlockWithTypeLoss:(id)block { ... }
[obj takeBlockWithTypeLoss:^{ ... }];
В таких случаях, когда документ был написан, ARC не копировал блок. Если вызываемый метод выполняет операцию, которая сохраняет переданный блок, возникает проблема, так как значение сохранения не находится в куче. (Обратите внимание, что блок должен быть стеком, выделенным для возникновения проблемы. Буквенные блоки, которые не ссылаются на переменные в своей среде, статически распределены, а также литеральный блок, который сначала сохраняется в локальной переменной с сильным владением по умолчанию, а затем передается к способу будут скопированы.)
Этот случай является примером потери типа, значение, известное как тип блока, передается как id
, теряющее информацию о типе. Компилятор всегда может определить такие точки, поэтому почему (или сделал ..) ARC не копирует блок? Ответ, данный в прошлом, просто один из эффективности, копия может быть не указана, и большое количество ненужных копий является хитом производительности.
Однако текущий компилятор (Xcode 4.6.1) появляется обрабатывать этот один оставшийся случай, в точке потери типа блок-копируется в кучу. Если кто-нибудь может показать, что это теперь задокументировано (или вы уверены, что ваш компилятор справляется с этим случаем, например, путем кодирования проверки), тогда будет отображаться Block_copy()
(или [block copy]
), если не тогда, когда происходит потеря типа, это должно быть используемый.
Добавление: июнь 2013
Как показали this question есть случай, что Xcode 4.6.3/Clang 4.2 делает не ручку. Когда блок передается как один из аргументов переменной в вариационный метод, компилятор автоматически не продвигает блок стека в кучу. Это подслучае потери типа, упомянутое выше.
Таким образом, текущие компиляторы тока не обрабатываются, что указывает на то, что компилятор, поддерживающий больше, чем спецификация, недокументирован - эта поддержка является неполной (хотя это не теоретическая причина, что она должна быть).
Как и прежде, если есть потеря типа, тогда компилятор может не выполнять автоматическое продвижение блока (но это может быть проверено, если это необходимо), случаи, не связанные с потерей типа, обрабатываются автоматически в соответствии с спецификацией.
(BTW. older question упоминается в комментарии к вышеупомянутому вопросу в настоящее время один из случаев, предусмотренных в спецификации и обрабатываются правильно компилятором.)
Я предполагаю, что это означает, что все, что вы возвращаетесь не значение, которое сохраняется после возвращения функции ... – Floris
См. http://stackoverflow.com/questions/6147940/blocks-and-stack – sfstewman