8

I want to declare a block type which take one parameter that is the same block type. It's just like this:

typedef void (^BlockInBlock) (BlockInBlock block);

I know the declaration is not valid. But I wonder if there is any possible way to implement recursive block which take just one parameter that is the same block type.


I'm trying finding a way to implement aspect-oriented programming (AOP) in Objective-C using block. Here are my questions about how to implement that.

Further Question 1:

How to implement a variadic function which takes many Blocks I described above and is ended up with nil, and I could invoke that function with many blocks until meets nil? It would be like this:

@interface NSObject(AOP)
- (void) invokeBlockInBlock:(BlockInBlock) headBlock, ...{
    va_list blockList;
    va_start(blockList, headBlock);

    // Invoke recursive blocks here until the value of va_arg(blockList, BlockInBlock) is nil
    // it would be like: block1(self, block2(self, block3(self, block4(...))));

    va_end(blockList);
}
@end

Further Question 2:

What if the recursive block has a return value?


Additional Question about C language:

Is it possible to declare a C function which take one parameter that is a C function pointer, and that C function pointer's function also takes another C function pointer?

Xaree Lee
  • 3,188
  • 3
  • 34
  • 55
  • 2
    See http://stackoverflow.com/questions/793449/recursive-declaration-of-function-pointer-in-c for your question regarding C. Without having given it a lot of thought, I suspect that the block question will wind up being similar. – Rob Napier Sep 13 '13 at 17:38

2 Answers2

11

that may be similar you are looking for:

typedef void (^Block)(id);

literally, it will cause an infinite recursive loop:

Block _block;
_block = ^(Block block) {
    if (block) block(block);
};

_block(_block);

however the parameter could be any id not only the exact same Block, but it represents how you pass the same block as parameter for the same block.

so, that would be the idea.

holex
  • 23,961
  • 7
  • 62
  • 76
4

It is much easier to do this by capturing the block in an __block reference. Actually, forward declaration of generic types in C are simply not supported. So, this may be the only solution?

__block void(^strawberryFields)();
strawberryFields = ^{ strawberryFields(); };
strawberryFields();

Note that if you are planning on dispatching that block asynchronously, you must copy it prior to assignment (this might no longer be necessary under ARC):

__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               strawberryFields);
bbum
  • 162,346
  • 23
  • 271
  • 359
  • Your declaration did not take another block as a parameter. It's not what I want. Anyway, thank you for your answer. – Xaree Lee Sep 14 '13 at 00:11
  • Any way to do this without the retain cycle? (under ARC) Xcode 5 warns on line 2 "Capturing 'strawberryFields' strongly in this block is likely to lead to a retain cycle" and Instruments testing seems to validate that there is a leak here (assuming you add code to avoid infinite recursion: – Dad Nov 15 '13 at 23:48
  • `__block int counter = 4; __block void(^strawberryFields)(); strawberryFields = [^{ if ( counter-- > 0 ) strawberryFields(); else NSLog(@"bye"); } copy]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), strawberryFields); ` – Dad Nov 15 '13 at 23:48
  • ugh. sorry about that formatting. Comments aren't great for code it appears (or I'm missing a trick). – Dad Nov 15 '13 at 23:51
  • This http://stackoverflow.com/questions/19884403/recursive-block-and-retain-cycles-in-arc/19885551#19885551 claims that `__block` AND `__weak` are required but I'm still seeing warnings that "Assigning block literal to a weak variable; object will be released after assignment" and it's not 100% clear to me that cascading assignments to strong var is going to prevent exactly that in all cases (may now due to how the compiler optimizes things, but is that something we can count on?) – Dad Nov 16 '13 at 00:08