如何实现递归块?

8
我想声明一个块类型,它需要一个参数,该参数是相同的块类型。就像这样:
typedef void (^BlockInBlock) (BlockInBlock block);

我知道这个声明是无效的。但我想知道是否有可能实现递归块,该块只需要一个参数,即相同的块类型。
我正在寻找一种使用block在Objective-C中实现面向切面编程(AOP)的方法。以下是关于如何实现该功能的问题。
进一步问题1:
如何实现一个可变参数函数(variadic function),它接受上述多个Block,并以nil结束,我可以使用多个块调用该函数,直到遇到 nil?就像这样:
@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

进一步问题2:

如果递归块有返回值怎么办?


关于C语言的额外问题:

是否可以声明一个C函数,它接受一个参数,该参数是一个C函数指针,并且该C函数指针的函数还接受另一个C函数指针?


2
请参考 https://dev59.com/4XRA5IYBdhLWcg3w4SDo 了解有关 C 的问题。虽然我没有仔细思考,但我认为块问题最终会变得相似。 - Rob Napier
2个回答

11

可能与您正在寻找的内容相似:

typedef void (^Block)(id);

实际上,这会导致无限递归循环:

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

_block(_block);

然而,参数可以是任何id,而不仅仅是完全相同的Block,但它代表了您如何将相同的块作为参数传递给相同的块。

因此,这会是个好主意


3
有趣的是,每当发布这些例子时,每个人都会选择无限递归... :) - bbum
很酷。是否有可能让2个或更多这些块在循环中相互调用?例如:块A -> 块B -> 块C -> 块A -> ... - Xaree Lee
@李岡諭,是的,这是可能的。 - holex
请查看我的最新更新的问题,关于如何实现连续调用多个代码块。非常感谢! - Xaree Lee

4

通过捕获块并引用__block,可以更轻松地完成此操作。实际上,在C语言中,泛型类型的前向声明根本不受支持。因此,这可能是唯一的解决方案?

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

请注意,如果您计划异步分派该块,则必须在分配之前复制它(在ARC下可能不再需要此操作):

请注意,如果您计划异步分派该块,则必须在分配之前复制它(这在ARC下可能不再需要):

__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               strawberryFields);

您的声明没有将另一个块作为参数。这不是我想要的。无论如何,感谢您的回答。 - Xaree Lee
有没有不使用保留循环的方法来实现这个?(在ARC下)Xcode 5在第2行发出警告:“在此块中强烈捕获'strawberryFields'可能会导致保留循环”,而Instruments测试似乎证实这里存在泄漏(假设您添加了代码以避免无限递归: - Dad
`__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
抱歉,格式出了点问题。评论似乎不适合代码(或者我还有什么技巧没学到)。 - Dad
这个网址https://dev59.com/UGIj5IYBdhLWcg3wx38x#19885551声称`__block`和`__weak`是必需的,但我仍然看到警告:'Assigning block literal to a weak variable; object will be released after assignment',而且对于强变量的连锁赋值是否会完全防止这种情况并不十分清楚(也许由于编译器如何优化事物,但这是我们可以指望的吗?) - Dad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接