在 Objective-C/C 中,你能写一个结合 2 个块的函数吗? [英] In Objective-C/C, can you write a function that combines 2 blocks?

查看:21
本文介绍了在 Objective-C/C 中,你能写一个结合 2 个块的函数吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常发现自己创建了一个包装器"块,它只是用于执行许多其他块,通常具有相同的类型签名.

I often find myself creating a "wrapper" block which just serves to execute a number of other blocks, usually with the same type signature.

假设我有 2 个具有相同类型签名的块:

Say I have 2 blocks with the same type signature:

MyBlockT block1 = ^(NSString *string, id object) {
    //1 does some work
};

MyBlockT block2 = ^(NSString *string, id object) {
    //2 does some other work
};

有没有办法实现魔术函数 Combine() 需要 2 个块:

Is there some way to implement the magic function Combine() which would take 2 blocks:

MyBlockT combinedBlock = Combine(block1, block2); //hypothetical function

并且相当于做:

MyBlockT combinedBlock = ^(NSString *string, id object) {
    block1(string, object);
    block2(string, object);
};

我知道这只对返回 void 的块有意义,但这就是我感兴趣的全部.

I know this only makes sense with blocks that return void, but that's all I'm interested in.

Combine 函数只需要包含 2 个块,如果我有更多,我可以将它们链接起来.我对如何实施这一点或是否有可能感到束手无策.

The Combine function needs only take in 2 blocks, if I have more I can just chain them. I'm at wits end on how to go about implementing this or whether it's even possible.

附:如果解决方案涉及 C 宏,我不介意

P.S. I wouldn't mind if the solution involved C macros

编辑

我希望能够将生成的块用作方法参数,例如:

I'd like to be able to use the resulting block as a method argument, e.g.:

[UIView animateWithDuration:1 animations:someCombinedBlock];

推荐答案

现在在 GitHub 上,WoolBlockInvocation

Now up on GitHub, WoolBlockInvocation!

这是一对类,WSSBlockInvocationWSSBlockSignature,以及一些支持代码,它们利用 libffi 和 ObjC @encode 字符串编译器为 Blocks 生成的它允许您调用具有相同参数集的整个 Block 列表.

This is a pair of classes, WSSBlockInvocation and WSSBlockSignature, along with some supporting code, that leverage libffi and the ObjC @encode strings which the compiler generates for Blocks to allow you to invoke a whole list of Blocks with the same set of arguments.

可以将任意数量的块添加到调用对象中,前提是它们的签名(即返回类型以及参数的数量和类型)匹配.在调用对象上设置参数后,可以依次调用 Blocks,并将返回值(如果有)存储起来以供以后访问.

Any number of Blocks can be added to an invocation object, provided their signatures -- meaning return type and number and types of arguments -- match. After setting arguments on the invocation object, the Blocks can be invoked in turn, with the return values, if any, stored for later access.

invocationBlock 方法的 WSSBlockInvocation.

- (id)invocationBlock
{
    return [^void (void * arg1, ...){
        [self setRetainsArguments:YES];
        va_list args;
        va_start(args, arg1);
        void * arg = arg1;
        NSUInteger numArguments = [blockSignature numberOfArguments];
        for( NSUInteger idx = 1; idx < numArguments; idx++ ){

            [self setArgument:&arg atIndex:idx];

            arg = va_arg(args, void *);
        }
        va_end(args);

        [self invoke];

    } copy];
}

这会返回一个 Block,它 (ab) 使用 varargs 功能来推迟分配参数,直到封装的 Block 本身被实际调用.因此,您可以执行以下操作:

This returns a Block that (ab)uses varargs functionality to defer assigning arguments until that encapsulating Block is actually invoked itself. You can thus do the following:

WSSBlockInvocation * invocation = [WSSBlockInvocation invocationWithBlocks:@[animationBlockOne, animationBlockTwo]];

void (^combinedAnimation)(void) = [invocation invocationBlock];

[UIView animateWithDuration:1 animations:combinedAnimation];

当然,如果你只是担心动画块,不带参数也没有返回值,构造一个包装块是微不足道的:

Of course, if you're just worried about Blocks for animations, that take no arguments and have no return value, constructing a wrapper Block is trivial:

void (^combinedAnimation)(void) = ^{
    animationBlock();
    anotherAnimationBlock();
    // etc.
};

如果你需要包装一组块并使用相同的参数集调用它们,你只需要我的代码.

You only need my code if you need to wrap a set of Blocks and invoke them all with the same set of arguments.

注意我已经在 x86_64 上的 OS X 上测试过这个,但没有在任何其他平台上.我希望它可以在 iOS 下的 ARM 上运行,但是 varargs 以不可移植"而著称,而且可能不是.警告编译器,如果出现问题,请告诉我.

N.B. I have tested this on OS X on x86_64, but not on any other platform. I hope it works on ARM under iOS, but varargs is famously "not portable" and it may not. Caveat compilor, and let me know if something breaks.

这篇关于在 Objective-C/C 中,你能写一个结合 2 个块的函数吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆