Перед прочтением рекомендую прочитать первую часть. В первой части мы узнали как создавать блоки и хранить их в переменных, передавать в методы и вызывать их. В этой части поговорим об особенностях использования блоков.
Взаимодействие с внешними переменными
Рассмотрим пример:
BOOL flag = YES;
void(^block)(NSString *) = ^(NSString* s)
{
if ( flag )
NSLog(@"String: %@", s);
};
block(@"Hello, World");
Тут все просто — блок выводит в консоль входящую строку, если флаг установлен в YES. Если мы сделаем вот так:
BOOL flag = YES;
void(^block)(NSString *) = ^(NSString* s)
{
if ( flag )
NSLog(@"String: %@", s);
};
flag = NO;
block(@"Hello, World");
Строка всеравно появиться в консоли, хотя флаг выставлен в NO. В чем же дело? Все дело в том, что блок копирует значение всех переменных и далее использует скопированное значение. Это относится к простейшим типам и структурам (не к указателям на объекты). Если мы хотим, чтобы блок не копировал значение переменной, а использовал ее истинное значение, необходимо пользоваться модификатором __block.
__block BOOL flag = YES;
void(^block)(NSString *) = ^(NSString* s)
{
if ( flag )
NSLog(@"String: %@", s);
};
flag = NO;
block(@"Hello, World");
Теперь, благодаря __block, блок будет использовать истинное значение переменной flag и не выведет строку.
А как же обстоят дела с указателями на объекты? По-умолчанию блок вызывает retain для всех указателей на объекты, которые в нем используются. Если использовать модификатор __block то retain для них не вызывается.
На этом все. В следующей части мы рассмотрим типы блоков и экземплярами каких классов они являются.
