3

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

1

3 Answers 3

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);
    };
}
Sign up to request clarification or add additional context in comments.

Comments

3

Is this possible?

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

5 Comments

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?
No wrapping required -- a block is an Objective-C object. You can store them in an NSArray (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.
How can we know when the block at index n has completed so that we can move onto n+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.
you had me at 'i think youre thinking that blocks always run asynchronously' ;)
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.

3 Comments

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.
But, as blocks are opaque, what would it mean to "share state"? You couldn't see any of it even if it were shared.
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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.