Блоки, стеки и кучи
Используя Xcode 4.2 и ARC, я написал следующий код, прежде чем понял, как нужно копировать блоки из стека в кучу.
-(void) downloadWithBlock:(void (^)(void))callbackBlock;
{
// start the data download in the background...
NSOperation *backgroundOperation = [NSBlockOperation blockOperationWithBlock:^{
// synchronous download code
}];
[backgroundOperationQueue addOperation:backgroundOperation];
NSOperation *foregroundOperation = [NSBlockOperation blockOperationWithBlock:^{
callbackBlock();
}];
[foregroundOperation addDependency:backgroundOperation];
[[NSOperationQueue mainQueue] addOperation:foregroundOperation];
}
Код работает, но я не доверяю ему, потому что я его не понимаю. В другом разделе кода я столкнулся с ошибками приложения при вызове блоков, которые хранились в ivars, без использования -copy. Это заставило меня задуматься, должен ли этот раздел кода быть переписан так:
-(void) downloadWithBlock:(void (^)(void))callbackBlock;
{
void(^heapBlock)(void) = [callbackBlock copy];
// start the data download in the background...
NSOperation *backgroundOperation = [NSBlockOperation blockOperationWithBlock:^{
// synchronous download code
}];
[backgroundOperationQueue addOperation:backgroundOperation];
NSOperation *foregroundOperation = [NSBlockOperation blockOperationWithBlock:^{
heapBlock();
}];
[foregroundOperation addDependency:backgroundOperation];
[[NSOperationQueue mainQueue] addOperation:foregroundOperation];
}
Моя единственная задача - лучше понять, как работают указатели блоков. Является ли любой из этих разделов кода приемлемым? Вызывает ли вызов блока внутри другого блока компилятор вставить скрытую операцию Block_copy?
1 ответ
Не только вызов блока внутри блока, но любая прямая ссылка на него вызовет копию. В том числе передавая это как аргумент чему-то еще. То же самое касается типов ObjC в блоке (за исключением того, что это просто сохранение, а не их копия).