在Objective-C / C,你可以写,结合2个街区的功能? [英] In Objective-C/C, can you write a function that combines 2 blocks?

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

问题描述

我经常发现自己创造了包装块刚刚供应与同类型的签名来执行一些其他块,通常

说我有2个街区,与同类型签名:

  MyBlockT块1 = ^(* NSString的字符串,ID对象){
    // 1做了一些工作
};MyBlockT块2 = ^(* NSString的字符串,ID对象){
    // 2做一些其他的工作
};

有一些方法来实现的神奇功能联合()这将需要2块:

  MyBlockT combinedBlock =结合(块1,块2); //假设的功能

和相当于做:

  MyBlockT combinedBlock = ^(* NSString的字符串,ID对象){
    块1(字符串对象);
    块2(字符串对象);
};

我知道这才有意义与返回无效,但仅此而已,我感兴趣的东西。

联合功能需求只在2块,如果我有更多的我就可以把它们连。我在上如何去实现这还是它甚至有可能束手无策。

P.S。我不会介意,如果方案包括C宏

修改

我希望能够用得到的嵌段作为方法的参数,例如:

  [UIView的animateWithDuration:1动画:someCombinedBlock];


解决方案

现在了在GitHub上, WoolBlockInvocation

这是一对类, WSSBlockInvocation WSSBlockSignature ,以及一些配套code,即杠杆libffi和编译器生成的模块,使您可以调用块的整个列表与同一组参数的ObjC @恩code 字符串。

块的任意数量可以被添加到调用对象,条件是它们的签名 - 这意味着参数返回类型和数量和类型 - 匹配。调用对象上设置参数之后,该块可以反过来被调用,用返回值,如果有的话,存储供以后访问。

这是你特别感兴趣的一块,缝纫,阻止列表成一个单一的块,由<一个提供href=\"https://github.com/woolsweater/WoolBlockInvocation/blob/master/WoolBlockInvocation/WSSBlockInvocation.m#L254\"相对=nofollow> invocationBlock 的方法 WSSBlockInvocation

   - (ID)invocationBlock
{
    返回[^无效(无效* ARG1,...){
        [个体经营setRetainsArguments:YES];
        va_list的ARGS;
        的va_start(参数,ARG1);
        无效* ARG = ARG1;
        NSUInteger numArguments = [blockSignature numberOfArguments]
        为(NSUInteger IDX = 1; idx的&下; numArguments; IDX ++){            [个体经营setArgument:放大器; ARG atIndex:IDX];            ARG =在va_arg(参数,无效*);
        }
        va_end用来(参数);        [自我调用]    }副本];
}

这会返回一个块是(AB)使用可变参数的功能推迟分配参数,直到封装块实际上是调用本身。因此,你可以做到以下几点:

  WSSBlockInvocation *调用= [WSSBlockInvocation invocationWithBlocks:@ [animationBlockOne,animationBlockTwo]];无效(^ combinedAnimation)(无效)= [调用invocationBlock][UIView的animateWithDuration:1动画:combinedAnimation];

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

 无效(^ combinedAnimation)(无效)= ^ {
    animationBlock();
    anotherAnimationBlock();
    //等等。
};

您只有当你需要用一组块,并调用它们都具有相同的组参数需要我的code。

N.B。我在OS X在x86_64测试这一点,但未在其他任何平台即可。我希望它适用于iOS下ARM,但可变参数是有名的不可移植,它可能不会。买者compilor,让我知道,如果东西坏了。

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

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
};

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

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

and be equivalent to doing:

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

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

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.

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

EDIT

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

[UIView animateWithDuration:1 animations:someCombinedBlock];

解决方案

Now up on GitHub, WoolBlockInvocation!

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.

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.

The piece that you're particularly interested in, sewing that list of Blocks up into a single Block, is provided by the invocationBlock method of 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];
}

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.

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天全站免登陆