3

I want to dynamically add code to a block variable, or merge or concatenate a block with another block. Is this possible?

eric
  • 4,863
  • 11
  • 41
  • 55
  • possible duplicate of [What happens to a block at compile time, and can I create one at runtime?](http://stackoverflow.com/questions/16323089/what-happens-to-a-block-at-compile-time-and-can-i-create-one-at-runtime) – Caleb Jan 28 '14 at 18:25

3 Answers3

5

One way of doing it is creating a block that calls the block to be "expanded" before performing its own functions.

For example, consider the example below that adds logging functionality to an arbitrary block passed into it:

typedef void (^MyBlock)(int);

-(MyBlock) expand:(MyBlock)nested {
    return ^(int x) {
        nested(x);
        NSLog("The value of x = %d", x);
    };
}

The cumulative effect of calling the block produced by expand: is that of invoking the original block, followed by an operation from the expanded block. You can take it further, to create an appendBlock method:

-(MyBlock) appendBlock:(MyBlock)second toBlock:(MyBlock)first {
    return ^(int x) {
        first(x);
        second(x);
    };
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

Is this possible?

No, but you can create a collection of blocks and execute them sequentially.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Would you give an example of assigning a block to a collection? Would it need to be a c-array since a block is not an obj? Or can you somehow wrap a block within another object for storage into a NSMutableArray? – eric Jan 28 '14 at 18:30
  • 1
    No wrapping required -- [a block is an Objective-C object](https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/bxOverview.html#//apple_ref/doc/uid/TP40007502-CH3-SW2). You can [store them in an NSArray](http://stackoverflow.com/q/7997666/643383) (or other Obj-C collection), or you can create another block that takes two or more blocks as parameters and executes them one after another, as dasblinkenlight has nicely illustrated. – Caleb Jan 28 '14 at 19:42
  • How can we know when the block at index n has completed so that we can move onto n+1? – eric Jan 30 '14 at 16:15
  • 1
    I think you're thinking that blocks always run asynchronously, but that's not the case at all. If you have a block assigned to a variable, you can invoke the block using the variable just like you would with a function pointer: `for (MyBlockType someBlock in listOfBlocks) { someBlock(); }` Async execution really only happens if you run the block on another thread or queue, like when you use GCD's `dispatch_async()` function to invoke the block. – Caleb Jan 30 '14 at 17:08
  • 1
    you had me at 'i think youre thinking that blocks always run asynchronously' ;) – eric Jan 30 '14 at 18:11
1

Sure - just create a new block, which makes use of the original in whatever compositional way you'd like. If you've got block1 and block2, you might create:

   someCodeBefore = ^myBlockType(block1) {
     someCode()
     thatIWantBefore();
     block1();
   }

   someCodeAfter = ^myBlockType(block1) {
     block1();
     someCode()
     thatIWantAfterBlock1();
   }

   composedBlocks = ^myBlockType(block1, block2) {
     block1();
     block2();
   }

Just make sure you're copying the blocks correctly.

Adam Wright
  • 48,938
  • 12
  • 131
  • 152
  • That's really not the same as merging/concatenating blocks together. You still have separate blocks, each with its own state, rather than a single block with shared state. – Caleb Jan 28 '14 at 18:26
  • But, as blocks are opaque, what would it mean to "share state"? You couldn't see any of it even if it were shared. – Adam Wright Jan 28 '14 at 18:41
  • Exactly -- you can use blocks in combination, and you can have a single block that contains other blocks, but you can't *merge* two blocks into a single block (which is what I understood the OP to be asking about). – Caleb Jan 28 '14 at 19:21