Что означает ключевое слово "__block"?
Что именно делает __block
Ключевое слово в Objective-C означает? Я знаю, что это позволяет вам изменять переменные внутри блоков, но я хотел бы знать...
- Что именно он говорит компилятору?
- Это делает что-нибудь еще?
- Если это все, что нужно, то зачем это нужно?
- Это где-нибудь в документах? (Я не могу найти это).
8 ответов
Он сообщает компилятору, что любая помеченная им переменная должна обрабатываться особым образом, когда она используется внутри блока. Обычно переменные и их содержимое, которые также используются в блоках, копируются, поэтому любая модификация этих переменных не отображается за пределами блока. Когда они отмечены __block
изменения, сделанные внутри блока, также видны за его пределами.
Пример и дополнительную информацию см. В разделе Тип хранилища __block в темах по программированию блоков Apple.
Важный пример:
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'
}
В этом примере оба localCounter
а также localCharacter
модифицируются перед вызовом блока. Однако внутри блока только модификация localCharacter
было бы видно, благодаря __block
ключевое слово. И наоборот, блок может изменить localCharacter
и эта модификация видна за пределами блока.
@bbum подробно описывает блоки в сообщении блога и затрагивает тип хранилища __block.
__block - это отдельный тип хранилища
__Block - это тип хранения, как и static, auto и volatile. Он сообщает компилятору, что хранилище переменной должно управляться по-другому.
...
Однако для переменных __block блок не сохраняется. Это зависит от вас, чтобы сохранить и отпустить, по мере необходимости.
...
Что касается вариантов использования вы найдете __block
иногда используется, чтобы избежать сохранения циклов, так как он не сохраняет аргумент. Типичным примером является использование себя.
//Now using myself inside a block will not
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;
Обычно, когда вы не используете __block, блок будет копировать (сохранять) переменную, поэтому даже если вы измените переменную, блок будет иметь доступ к старому объекту.
NSString* str = @"hello";
void (^theBlock)() = ^void() {
NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints @"hello"
В этих 2 случаях вам нужен __block:
1. Если вы хотите изменить переменную внутри блока и ожидать, что она будет видна снаружи:
__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
str = @"how are you";
};
theBlock();
NSLog(@"%@", str); //prints "how are you"
2. Если вы хотите изменить переменную после того, как объявили блок и ожидаете, что блок увидит изменение:
__block NSString* str = @"hello";
void (^theBlock)() = ^void() {
NSLog(@"%@", str);
};
str = @"how are you";
theBlock(); //prints "how are you"
__block - это спецификатор хранилища, который можно использовать двумя способами:
Отмечает, что переменная находится в хранилище, которое используется совместно с лексической областью исходной переменной и любыми блоками, объявленными в этой области. И clang сгенерирует структуру для представления этой переменной и будет использовать эту структуру по ссылке (а не по значению).
В MRC можно использовать __block, чтобы избежать сохранения переменных объекта, захваченных блоком. Осторожно, это не работает для ARC. В ARC вы должны использовать вместо __weak.
Вы можете обратиться к Apple Doc для получения подробной информации.
__block
тип хранилища, который используется для того, чтобы сделать переменные в области видимости изменяемыми, более откровенно говоря, если вы объявите переменную с помощью этого спецификатора, его ссылка будет передана в блоки, а не в копию только для чтения. Дополнительные сведения см. в разделе " Программирование блоков в iOS".
Надеюсь, что это поможет вам
предположим, у нас есть код вроде:
{
int stackVariable = 1;
blockName = ^()
{
stackVariable++;
}
}
это выдаст ошибку типа "переменная не присваивается", потому что переменная стека внутри блока по умолчанию неизменна.
добавление __block(модификатор хранилища) перед объявлением делает его изменяемым внутри блока, т.е. __block int stackVariable=1;
В дополнение к новому типу блока мы также вводим новый спецификатор хранения __block для локальных переменных. [testme: объявление __block внутри литерала блока] Квалификатор хранилища __block является взаимоисключающим с существующими квалификаторами локального хранилища auto, register и static.[testme] Переменные, квалифицированные с помощью __block, действуют так, как если бы они находились в выделенном хранилище, и это хранилище автоматически восстанавливается после последнего использования указанной переменной. Реализация может выбрать оптимизацию, когда хранилище изначально автоматическое и только "перемещается" в выделенное (кучное) хранилище после Block_copy ссылающегося блока. Такие переменные могут быть видоизменены как обычные переменные.
В случае, когда переменная __block представляет собой блок, необходимо предположить, что переменная __block находится в выделенном хранилище и, как таковая, должна ссылаться на блок, который также находится в выделенном хранилище (что это является результатом операции Block_copy). Несмотря на это, нет никаких условий для выполнения Block_copy или Block_release, если реализация обеспечивает начальное автоматическое хранение блоков. Это связано с тем, что несколько потоков пытаются обновить разделяемую переменную, а также необходимость синхронизации при удалении старых значений и копировании новых. Такая синхронизация выходит за рамки данной языковой спецификации.
Для получения подробной информации о том, к чему должна компилироваться переменная __block, см. Спецификацию реализации блока, раздел 2.3.
Это означает, что переменная, к которой относится префикс, доступна для использования в блоке.