如何在Objective-C中强制使用匿名块的参数?

时间:2013-08-16 10:54:38

标签: objective-c objective-c-blocks enforcement unused-variables

我在使用名为TransitionKit的库(帮助您编写状态机)时遇到了一种情况,我希望以回调的形式提供进入和退出操作。

可悲的是,回调包括两个完全无用的参数。典型的块必须如下所示:

^void (TKState *state, TKStateMachine *stateMachine) {
    // I TOTALLY don't want parameters `state` or `stateMachine` used here
};

(这是一个匿名代码块。如果您不清楚,请阅读块here

正如我在评论中所指出的那样,我真的不希望那些参数甚至在身体中提到。我试过简单地删除像this question中建议的参数名称,如下所示:

^void (TKState *, TKStateMachine *) {
     // I foobar all I like here
};

但遗憾的是代码无法编译:(。

如何在代码中强制执行此类参数的使用?

4 个答案:

答案 0 :(得分:2)

这是我能想到的。相当糟糕并且依赖于GCC poison编译指示,这不是标准的,而是GNU扩展 - 尽管如果你可能用clang编译它,它应该不是问题。

#define _state state
#define _stateMachine stateMachine

#pragma GCC poison state stateMachine

然后编译:

^(TKState *_state, TKStateMachine *_stateMachine) {
    do_something();
}

但这不是:

^(TKState *_state, TKStateMachine *_stateMachine) {
    do_something(state, stateMachine);
}

答案 1 :(得分:1)

你可以拥有一个带有一种块的函数,并返回另一个块,如下所示:

@class TKState, TKStateMachine; // here so this will compile

typedef void (^LongStateBlock)(TKState *state, TKStateMachine *stateMachine);

static inline LongStateBlock Adapter(void(^block)()) {

    void(^heapBlock)() = [block copy]; // forces block to be on heap rather than stack, a one-time expense

    LongStateBlock longBlock = ^(TKState *s __unused, TKStateMachine *sm __unused) {
        heapBlock();
    };

    // this is the non-ARC, MRR version; I'll leave ARC for the interested observer
    [heapBlock release];
    return [[longBlock copy] autorelease];
}

在实践中:

// this represents a library method
- (void)takesLongStateBlock:(LongStateBlock)longBlock
{
    // which hopefully wouldn't look exactly like this
    if (longBlock) longBlock(nil, nil);
}

- (void)yourRandomMethod
{
    [self takesLongStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
        NSLog(@"Gratuitous parameters, AAAAHHHH!");
    }];

    [self takesLongStateBlock:Adapter(^{
        NSLog(@"So, so clean.");
    })];

}

整个事情是gisted,应该在任何类中编译。当您拨打-yourRandomMethod时,它会按预期执行。

答案 2 :(得分:0)

AFAIK在创建块时无法执行所需的操作,在声明块变量时(参考块,以避免误解),您只能错过参数名称。

所以在这里你可以错过参数名称:

void (^myBlock)(SomeClass *);

但是当你创建一个块时不是这样:

myBlock = ^(SomeClass *o)
{
};

答案 3 :(得分:0)

我会写

^void (TKState *unused_state, TKStateMachine *unused_stateMachine) {
    // Anyone using unused_state or unused_stateMachine gets what they deserve.
};

当然有人可以使用这些参数。但无论你做什么,他们都可以改变代码。如果有人打算用脚射击自己,就没有阻止它们。