Reputation: 35002
I have two blocks declared as local variables. A networking block that calls a retry block on error, and a retry block that calls the networking block.
The retry block is called in several different error circumstances, hence using a block to eliminate duplicated code.
However, this scenario does not work due to the source code order of the declared blocks.
void (^upperBlock)() = ^{
// variable is used before it is declared.
lowerBlock(); // Error: implicit declaration of function `lowerBlock` is invalid in C99
};
void (^lowerBlock)() = ^{
upperBlock(); // ok!
};
It does not work to give the lower block a forward declaration, as the upper block captures the initial value of the forward declaration before the variable is reassigned (even if it is called later).
void (^lowerBlock)() = nil;
void (^upperBlock)() = ^{
lowerBlock(); // crash! block is `nil`
};
lowerBlock = ^{
// new value not assigned, despite `upperBlock` being *called* below this point
};
upperBlock()
I could use __block
on the lowerBlock, in which case the upperBlock will call the freshly assigned version of the variable. But using __block
seems like overkill for this scenario if another solution is possible.
Is there any inline, block-as-a-local-variable solution to allow the upper and lower blocks to reference each other?
Upvotes: 1
Views: 138
Reputation: 64002
Captures are by value with Blocks unless the variable is marked as __block
. That's the correct solution here.
If you declare lower
as a __block
variable, it will be captured as a reference rather than taken as a copy, and the upper
will see its "current" value when called:
__block BOOL proceedWithInfiniteRegress = YES;
__block dispatch_block_t lower;
dispatch_block_t upper = ^{
if( proceedWithInfiniteRegress ){
lower();
}
};
lower = ^{
proceedWithInfiniteRegress = NO;
NSLog(@"Hello, reference cycle!");
upper();
};
upper();
Upvotes: 1