Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a SELF pointer for blocks?

I'd like to recursively call a block from within itself. In an obj-c object, we get to use "self", is there something like this to refer to a block instance from inside itself?

like image 728
Arlen Anderson Avatar asked Jan 28 '11 03:01

Arlen Anderson


People also ask

What are blocks in OBJC?

Blocks are a language-level feature added to C, Objective-C and C++ which allow you to create distinct segments of code that can be passed around to methods or functions as if they were values. Blocks are Objective-C objects which means they can be added to collections like NSArray or NSDictionary.

Why do you generally create a weak reference when using self in a block?

For many of us, it's best practice to always use weak combined with self inside closures to avoid retain cycles. However, this is only needed if self also retains the closure. By adding weak by default you probably end up working with optionals in a lot of cases while it's actually not needed.

How do you write blocks in Objective C?

^blockName: Always remember that the block name is preceded by the ^ symbol. The block name can be any string you like, just like you name any other variable or method. Remember that both the ^ and the block name are enclosed in parentheses ().


2 Answers

Fun story! Blocks actually are Objective-C objects. That said, there is no exposed API to get the self pointer of blocks.

However, if you declare blocks before using them, you can use them recursively. In a non-garbage-collected environment, you would do something like this:

__weak __block int (^block_self)(int);
int (^fibonacci)(int) = [^(int n) {
    if (n < 2) { return 1; }
    return block_self(n - 1) + block_self(n - 2);
} copy];

block_self = fibonacci;

It is necessary to apply the __block modifier to block_self, because otherwise, the block_self reference inside fibonacci would refer to it before it is assigned (crashing your program on the first recursive call). The __weak is to ensure that the block doesn't capture a strong reference to itself, which would cause a memory leak.

like image 141
zneak Avatar answered Sep 23 '22 18:09

zneak


The following recursive block code will compile and run using ARC, GC, or manual memory management, without crashing, leaking, or issuing warnings (analyzer or regular):

typedef void (^CountdownBlock)(int currentValue);

- (CountdownBlock) makeRecursiveBlock
{
    CountdownBlock aBlock;
    __block __unsafe_unretained CountdownBlock aBlock_recursive;
    aBlock_recursive = aBlock = [^(int currentValue)
    {
        if(currentValue >= 0)
        {
            NSLog(@"Current value = %d", currentValue);
            aBlock_recursive(currentValue-1);
        }
    } copy];
#if !__has_feature(objc_arc)
    [aBlock autorelease];
#endif

    return aBlock;
}

- (void) callRecursiveBlock
{
    CountdownBlock aBlock = [self makeRecursiveBlock];

    // You don't need to dispatch; I'm doing this to demonstrate
    // calling from beyond the current autorelease pool.
    dispatch_async(dispatch_get_main_queue(), ^
                   {
                       aBlock(10);
                   });
}

Important considerations:

  • You must copy the block onto the heap manually or else it will try to access a nonexistent stack when you call it from another context (ARC usually does this for you, but not in all cases. Better to play it safe).
  • You need TWO references: One to hold the strong reference to the block, and one to hold a weak reference for the recursive block to call (technically, this is only needed for ARC).
  • You must use the __block qualifier so that the block doesn't capture the as-yet unassigned value of the block reference.
  • If you're doing manual memory management, you'll need to autorelease the copied block yourself.
like image 31
Karl Avatar answered Sep 24 '22 18:09

Karl