In Objective-C/C, can you write a function that combines 2 blocks?

前端 未结 5 1280
北荒
北荒 2020-12-12 00:30

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 wit

5条回答
  •  死守一世寂寞
    2020-12-12 01:03

    Here is a fun abuse of varargs:

    id combine(id block, ...)
    {
            NSMutableArray *blocks = [NSMutableArray array];
            //[blocks addObject:block];
            va_list objlist;
            va_start(objlist, block);
            //while((obj = va_arg(ap, id))) { // }
            for(id obj = block; obj; obj = va_arg(objlist, id)) {
                    [blocks addObject:[obj copy]];
            }
            va_end(objlist);
            void (^wrapper)(id,...) = ^(id arg, ...) {
                    NSMutableArray *args = [NSMutableArray array];
                    va_list arglist;
                    va_start(arglist, arg);
                    for(id x = arg; x; x = va_arg(arglist, id)) {
                            [args addObject:x];
                    }
                    va_end(arglist);
    
                    for(void (^blk)() in blocks) {
                            blk(args);
                    }
            };
            return [wrapper copy];
    }
    
    int main() {
            NSString *fmt = @"-%d-\n%@\n---";
            void (^foo)() = combine(^(NSArray *a){ NSLog(fmt, 1, a); },
                                    ^(NSArray *a){ NSLog(fmt, 2, a); }, nil);
            foo(@"first", @"second", nil);
            return 0;
    }
    

    You must define each block to accept an NSArray of arguments, and both the combine and resulting block invocation must have at least one argument and end in nil.

    If you know the method signature ahead of time, you can work around the NSArray and block arguments restriction by altering the wrapper block appropriately.

提交回复
热议问题