6

Насколько я понимаю, для хранения скалярных переменных блоком требуется тип памяти __block, но когда это необходимо для объектов? Я полагаю, что __weak следует использовать при записи саморекламы, которая будет использоваться внутри блока, но я не вижу, когда необходимо было бы использовать тип хранения __block для обычных объектов.Когда использовать ключевое слово __block в ссылках на объекты с ARC

+0

Кроме того, [что разница между __weak и __block ссылка?] (http://stackoverflow.com/questions/11773342/what-the-difference-between-weak-and-block-reference) –

+0

Я специально спрашиваю: когда тип хранения '__block' sh ould использовать для нескалярных ссылок на несамостоятельные объекты при использовании ARC? Если эти другие ссылки отвечают на этот вопрос, я пропустил его. – chinabuffet

+0

@chinabuffet: нет никакой разницы между тем, как он работает для скалярных типов и типов указателей объектов. – newacct

ответ

15

__block необходим для скалярных переменных, если вы хотите изменить их значение с помощью кода внутри блока. Захваченные скаляры отображаются как const внутри блока и поэтому не могут быть изменены. Если у вас есть указатель на объект, применяется одно и то же различие - сам захваченный указатель будет указателем const и поэтому не может быть изменен, но указанный объект может быть изменен кодом внутри блока. Если вы хотите изменить объект, на который указывает, то сам указатель должен измениться, и поэтому указатель должен быть объявлен с типом __block. Никогда не нужно объявлять сам объект как __block, но только указатель на объект, и только если указатель должен быть изменен.

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

__block переменные «под капотом» имеют дополнительный слой косвенности виды использования компилятора (и что вы не видите), включенных в блок, так что, когда блок копируется в кучу, поэтому они захваченное __block переменные , а невидимые указатели настроены так, чтобы указывать на новое местоположение кучи этих переменных __block. Это означает, что адрес переменной __block может измениться, поэтому будьте осторожны, если вы используете этот адрес. Вы также можете видеть, что переменная __block живет в некотором смысле «вне» блока, поэтому эти переменные могут считываться и модифицироваться из кода, внешнего по отношению к блоку.

Я был кратким, но вы можете найти лучшие объяснения здесь, перечислены в возрастающей сложности:

http://ios-blog.co.uk/tutorials/programming-with-blocks-an-overview/

http://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html

http://www.mikeash.com/pyblog/friday-qa-2011-06-03-objective-c-blocks-vs-c0x-lambdas-fight.html

+0

Итак, если блок передан как ссылка где-то, делает ли тот, который получает этот блок, как параметр, необходимо немедленно скопировать блок, чтобы использовать его в будущем? – chinabuffet

+0

Если ссылка на блок может пережить лексическую область (стек стека), в которой был определен блок, ее необходимо скопировать, чтобы переместить объект блока в кучу. Я думаю, было бы безопаснее делать копию при создании блока, чем иметь эти копии, происходящие в местах, удаленных от создания. – Fred

0

Они используются для переменных уровня функции. Они изменяются внутри блока (и охватывающей области) и сохраняются, если какой-либо ссылочный блок копируется в кучу. Переменные, локальные для охватывающей лексической области, объявленные с помощью модификатора хранилища __block, предоставляются посредством ссылки и поэтому изменяемы. Любые изменения отражаются в охватывающей лексической области, включая любые другие блоки, определенные в пределах той же охватывающей лексической области.

__block переменные, хранящиеся в памяти, которые разделены между лексической областью переменной и всеми блоками и блочными копиями, объявленными или созданными в лексической области переменной. Таким образом, хранилище сохранится при уничтожении кадра стека, если любые копии блоков, объявленных в пределах кадра, выйдут за пределы кадра (например, путем размещения где-то для последующего выполнения). Поэтому используйте их, когда вам нужно изменить объект внутри блока или когда вам понадобится объект после уничтожения фрейма стека.

Смежные вопросы