self
- это всего лишь захваченная переменная внутри блока и не ссылается на сам блок, поэтому как сама ссылка блока не имеет явной захваченной переменной для этой цели?
Как код внутри блока Objective-C ссылается на объект блока?
Ответ 1
__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
strawberryFields);
-
вы используете
__block
, потому что блок создаст копию значенияstrawberryFields
, когда будет создан блок, который будет перед назначением. -
вы также должны
copy
блокировать до любой другой операции копирования, иначе вы получите блок, который ссылается на исходную версию на стеке. -
обратите внимание, что приведенный выше код утечки блока. Где-то там должен быть
release
этого блока, чтобы сбалансировать копию.
Ответ 2
Я нашел этот шаблон работоспособным и стабильным для ARC (автоматический подсчет ссылок), как в сборках Debug, так и Release.
-(void) someMethod
{
// declare a __block variable to use inside the block itself for its recursive phase.
void __block (^myBlock_recurse)();
// define the block
void (^myBlock)() = ^{
// ... do stuff ...
myBlock_recurse(); // looks like calling another block, but not really.
};
// kickstart the block
myBlock_recurse = myBlock; // initialize the alias
myBlock(); // starts the block
}
Сначала я попробовал просто поместить модификатор __block
в myBlock
и использовать эту переменную непосредственно для рекурсии в реализации блока. Это работает в сборке ARC Debug, но ломается с EXC_BAD_ACCESS
в сборке Release. С другой стороны, удаление модификатора __block
вызывает предупреждение "переменная, не определенная при захвате блоком" (и я не хотел ее запускать и тестировал).
Ответ 3
Я никогда не пробовал это раньше, а не 100% уверен, что это полезно, если оно действительно, но, например:
typedef void (^BasicBlock)(void);
__block BasicBlock testBlock;
testBlock = ^{NSLog(@"Testing %p", &testBlock);};
testBlock();
Вероятно, вы указали переменную с __block, чтобы предотвратить цикл самообеспечения.
Ответ 4
Блок нуждается в некотором роде для извлечения собственной ссылки. Обычно это делается путем сохранения блока в свойстве класса.
Иногда вы можете не использовать свойство. Вот как вы это делаете без свойства:
__weak id weakSelf = self;
__block id block = ^{
if(weakSelf) {
// .. do whatever
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
}
else {
block = nil;
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
Главное, что нужно иметь в виду, это то, что все пути кода должны приводить к блоку = nil. Мы делаем это здесь, вызывая блок каждые 5 секунд, пока weakSelf не станет нулевым.
Ответ 5
Обратите внимание, что в ARC это немного отличается - переменные указателя объекта __block
по умолчанию сохраняются в ARC, в отличие от MRC. Таким образом, это вызовет цикл удержания. Необходимо, чтобы блок фиксировал слабую ссылку на себя (используя __weak
), чтобы не иметь цикла сохранения.
Однако нам все еще нужна сильная ссылка на блок где-то. Если нет сильных ссылок, блок (который находится на куче с момента его копирования) будет освобожден. Таким образом, нам нужны две переменные: одна сильная и одна слабая, а внутри блока используется слабый для ссылки:
__block __weak void(^weakBlock)();
void(^myBlock)();
weakBlock = myBlock = [^{ weakBlock(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
myBlock);