pkamb
pkamb

Reputation: 35002

Can two local variable blocks call each other? Scope issue due to order of declaration

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

Answers (1)

jscs
jscs

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

Related Questions