Ответ 1
ПРЕДУПРЕЖДЕНИЕ: переменная указателя блока "completeBlock" не инициализирована при захвате блоком
Это происходит потому, что блок-переменные, инициализированные для рекурсивного блока, нуждаются в хранилище __block
.
- Переменные внутри блока копируются, если не объявлены с помощью
__block
, и в этом случае они передаются в качестве ссылки. - Когда рекурсивный блок присваивается блочной переменной, создание происходит до назначения, и такое создание запускает переменную копию. Учитывая, что переменная еще не назначена, скопированная переменная будет плохим значением и приведет к сбою при запуске блока.
- Но если мы добавим
__block
, блок будет создан вместо ссылки на переменную. Затем переменная будет инициализирована в созданном блоке, и блок будет готов к использованию.
ПРЕДУПРЕЖДЕНИЕ: Захват "завершения" блокировки в этом блоке вероятен чтобы привести к циклу удержания
Это происходит потому, что блочная переменная является сильной ссылкой на блок, и блок сам ссылается на переменную (поскольку, как мы видели ранее, переменная имеет __block
, поэтому вместо нее она ссылается).
Итак, нам нужно
- Слабая ссылка на сильную переменную внутри блока.
- И сильная ссылка снаружи, чтобы предотвратить освобождение блока во время действия метода, в котором он создан.
void(^ completionBlock) (id obj, NSError *err, NSURLRequest *request); void(^ __block __weak weakCompletionBlock) (id obj, NSError *err, NSURLRequest *request); weakCompletionBlock = completionBlock = ^(id obj,NSError *err, NSURLRequest *request){ [self lengthyAsyncMethod:weakCompletionBlock]; };
Имя doLengthyAsynchronousOperationWithCompletionBlock
предполагает, что метод может пережить область метода, в которой создается блок. Учитывая, что компилятор не копирует блок, переданный в качестве аргумента, ответственность этого метода заключается в том, чтобы скопировать этот блок. Если мы используем этот блок с блочным кодом (например: dispatch_async()
), это происходит автоматически.
Если бы мы назначили этот блок переменной экземпляра, нам понадобится @property(copy)
и слабая ссылка на self внутри блока, но это не так, поэтому мы просто используем self.