Блоки и переменные
Эта статья описывает взаимодействие между блоками и переменными, включая управление памятью.
Типы переменной
В блочной организации объекта кода переменные могут быть обработаны пятью различными способами.
Можно сослаться на три стандартных типа переменной, как Вы были бы от функции:
Глобальные переменные, включая статические локальные переменные
Глобальные функции (которые не являются технически переменными),
Локальные переменные и параметры от объема включения
Блоки также поддерживают два других типа переменной:
На функциональном уровне
__block
переменные. Если какой-либо блок ссылки копируется в «кучу», они являются непостоянными в блоке (и объем включения) и сохраняются.const
импорт.
Наконец, в реализации метода, блоки могут сослаться на переменные экземпляра Objective C — посмотрите Переменные объекта и Основные переменные.
Соблюдающие правила применяются к переменным, используемым в блоке:
Глобальные переменные доступны, включая статические переменные, существующие в лексическом контексте включения.
Параметры, переданные блоку, доступны (точно так же, как параметры к функции).
(Нестатические) переменные штабеля, локальные для лексического контекста включения, получены как
const
переменные.Их значения приняты при блочном выражении в программе. Во вложенных блоках значение получено от самого близкого объема включения.
Переменные, локальные для лексического контекста включения, объявленного с
__block
модификатор хранения является предоставленным ссылкой и является непостоянным - также.Любые изменения отражаются в лексическом контексте включения, включая любые другие блоки, определенные в том же лексическом контексте включения. Они обсуждены более подробно в __ Тип блочной системы хранения.
Локальные переменные объявили в лексическом контексте блока, которые ведут себя точно как локальные переменные в функции.
Каждый вызов блока предоставляет новую копию той переменной. Эти переменные могут поочередно использоваться как
const
или переменные ссылкой в блоках включаются в блоке.
Следующий пример иллюстрирует использование локальных нестатических переменных:
int x = 123; |
void (^printXAndY)(int) = ^(int y) { |
printf("%d %d\n", x, y); |
}; |
printXAndY(456); // prints: 123 456 |
Как отмечено, пытаясь присвоить новое значение x
в блоке привел бы к ошибке:
int x = 123; |
void (^printXAndY)(int) = ^(int y) { |
x = x + y; // error |
printf("%d %d\n", x, y); |
}; |
Чтобы позволить переменной быть измененной в блоке, Вы используете __block
модификатор типа хранения — видит __ Тип блочной системы хранения.
__ тип блочной системы хранения
Можно указать, что импортированная переменная является непостоянной — т.е. чтение-запись — путем применения __block
модификатор типа хранения. __block
хранение является подобным, но взаимоисключающим из, register
, auto
, и static
типы хранения для локальных переменных.
__block
переменные живут в хранении, совместно использующемся лексическим контекстом переменной и всеми блоками и блочными копиями, объявленными или создаваемыми в лексическом контексте переменной. Таким образом, если какие-либо копии блоков, объявленных в кадре, останутся в силе вне конца кадра (например, будучи ставившимся в очередь где-нибудь для более позднего выполнения), хранение останется в силе после уничтожения стекового фрейма. Многократные блоки в данном лексическом контексте могут одновременно использовать совместно используемую переменную.
Как оптимизация, блочная система хранения начинается на штабеле — точно так же, как сами блоки делают. Если блок копируется с помощью Block_copy
(или в Objective C, когда блок отправляется a copy
), переменные копируются в «кучу». Таким образом, адрес a __block
переменная может изменяться в течение долгого времени.
Существует два дальнейших ограничения на __block
переменные: они не могут быть массивами переменной длины и не могут быть структурами, содержащими массивы переменной длины C99.
Следующий пример иллюстрирует использование a __block
переменная:
__block int x = 123; // x lives in block storage |
void (^printXAndY)(int) = ^(int y) { |
x = x + y; |
printf("%d %d\n", x, y); |
}; |
printXAndY(456); // prints: 579 456 |
// x is now 579 |
Следующий пример показывает взаимодействие блоков с несколькими типами переменных:
extern NSInteger CounterGlobal; |
static NSInteger CounterStatic; |
{ |
NSInteger localCounter = 42; |
__block char localCharacter; |
void (^aBlock)(void) = ^(void) { |
++CounterGlobal; |
++CounterStatic; |
CounterGlobal = localCounter; // localCounter fixed at block creation |
localCharacter = 'a'; // sets localCharacter in enclosing scope |
}; |
++localCounter; // unseen by the block |
localCharacter = 'b'; |
aBlock(); // execute the block |
// localCharacter now 'a' |
} |
Переменные объекта и основные переменные
Блоки предоставляют поддержку для Objective C и объектов C++ и других блоков, как переменные.
Объекты Objective C
Когда блок копируется, он создает сильные ссылки к переменным объекта, используемым в блоке. Если Вы используете блок в реализации метода:
При доступе к переменной экземпляра ссылкой сильная ссылка сделана, чтобы
self
;При доступе к переменной экземпляра значением сильная ссылка сделана на переменную.
Следующие примеры иллюстрируют две различных ситуации:
dispatch_async(queue, ^{ |
// instanceVariable is used by reference, a strong reference is made to self |
doSomethingWithObject(instanceVariable); |
}); |
id localVariable = instanceVariable; |
dispatch_async(queue, ^{ |
/* |
localVariable is used by value, a strong reference is made to localVariable |
(and not to self). |
*/ |
doSomethingWithObject(localVariable); |
}); |
Для переопределения этого поведения для определенной переменной объекта можно отметить его с __block
модификатор типа хранения.
Объекты C++
В целом можно использовать объекты C++ в блоке. В функции членства ссылки на задействованные переменные и функции через неявно импортированы this
указатель и таким образом кажется непостоянным. Существует два соображения, применяющиеся, если копируется блок:
Если у Вас есть a
__block
класс памяти для того, что было бы стековым объектом C++, тогда обычноеcopy
конструктор используется.При использовании какого-либо другого C++ стековый объект из блока это должно иметь a
const copy
конструктор. Объект C++ тогда копируется с помощью того конструктора.
Блоки
Если необходимый — все дерево может быть скопировано (с вершины), при копировании блока любые ссылки на другие блоки из того блока копируются. Если у Вас будут основные переменные, и Вы ссылаетесь на блок из блока, то тот блок будет скопирован.