Перед прочтением рекомендую прочитать первую часть. В первой части мы узнали как создавать блоки и хранить их в переменных, передавать в методы и вызывать их. В этой части поговорим об особенностях использования блоков.
Взаимодействие с внешними переменными
Рассмотрим пример:
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 для них не вызывается.
На этом все. В следующей части мы рассмотрим типы блоков и экземплярами каких классов они являются.