Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can code inside an Objective-C block reference the block object itself?

self is merely a captured variable inside a block and doesn't reference the block itself, so how does a block reference itself without having an explicit captured variable for that purpose?

like image 570
Steve Weller Avatar asked Mar 05 '11 02:03

Steve Weller


People also ask

How do blocks work in Objective-C?

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 .

What is closure in Objective-C?

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter's type to indicate that the closure is allowed to escape.

What is ID in Obj C?

id is a data type of object identifiers in Objective-C, which can be use for an object of any type no matter what class does it have. id is the final super type of all objects.


2 Answers

__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               strawberryFields);
  • you use the __block because the block will make a copy of the value of strawberryFields when the block is created which will be before the assignment.

  • you also must copy the block prior to any other copy operation or else you'll end up with a block that references the on-stack original version.

  • note that the above code leaks the block. Somewhere, there needs to be a release of that block to balance the copy.

like image 153
bbum Avatar answered Oct 04 '22 02:10

bbum


I found this pattern to work and stable for ARC (automatic reference counting), both in Debug and Release builds.

-(void) someMethod
{
    // declare a __block variable to use inside the block itself for its recursive phase.
    void __block (^myBlock_recurse)();

    // define the block
    void (^myBlock)() = ^{
        // ... do stuff ...
        myBlock_recurse(); // looks like calling another block, but not really.
    };

    // kickstart the block
    myBlock_recurse = myBlock; // initialize the alias
    myBlock(); // starts the block
}

Initially I tried just putting a __block modifier to myBlock and use that variable directly to recurse within the block's implementation. That works on the ARC Debug build but breaks with an EXC_BAD_ACCESS on the Release build. On the other hand removing the __block modifier raises a "variable not defined when captured by block" warning (and I was reluctant to run it and test).

like image 42
adib Avatar answered Oct 04 '22 03:10

adib