传递与签名不匹配的块参数

时间:2013-08-09 17:06:00

标签: objective-c objective-c-blocks

我正在使用基于块的API,偶然发现了一个场景,我传入的块参数的签名与方法所期望的typedef'd参数不匹配。令我惊讶的是,编译器似乎并不关心这一点,并且应用程序没有崩溃。这是预期的行为吗?例如:

typedef void(^MyBlock)();
typedef void(^MyBlockWithParam)(id param);

- (void)doWork {
    MyBlockWithParam block1 = ^(id param) {
        NSLog(@"block1: %@", param);
    };

    MyBlock block2 = ^{
        NSLog(@"block2");
    };

    [self loadData:block1];
    [self loadData:block2];
}

- (void)loadData:(MyBlockWithParam)block {
    block(@"foo");
}

3 个答案:

答案 0 :(得分:9)

提供空参数规范,如

typedef void(^MyBlock)();

表示“未指定”的参数。所以这两种类型是兼容的。将第一个声明更改为

typedef void(^MyBlock)(void);

指定该块不带参数,您将收到错误。

K& R C指定空参数列表表示“未指定”。 C块规范说块格式声明不正确(参见http://clang.llvm.org/docs/BlockLanguageSpec.html#block-variable-declarations:GCC和Clang都将K& R行为实现为语言扩展。

答案 1 :(得分:4)

来自Clang Blocks规范:

  

支持可变参数...参数。 [variadic.c] 不带参数的块必须在参数列表中指定void [voidarg.c]。如K& R所提供的,空参数列表不表示未指定的参数列表。注意:gcc和clang都支持K& R风格,以方便使用。

基本上,这是C语法的古老怪癖。在过去,C函数声明语法相当不同,空括号表示该函数可以传递任意数量的参数。为了向后兼容,编译器通常允许使用旧式函数声明语法。由于某种原因,Apple决定在块标准中同时拒绝这种语法,同时实际允许它与GCC和Clang中的块一起使用。

所以,长话短说:要声明一个块不带参数,你需要明确地将其键入为void(^MyBlock)(void)

答案 2 :(得分:3)

这是一件C事。具有空参数列表的函数或块原型意味着“函数(或块)接受您喜欢的任何参数”。如果你想传达该块应该没有参数,你需要明确地这样说:

typedef void(^MyBlock)(void)

这很大程度上是从ANSI之前的日子开始的,当时没有函数原型,所有函数声明(与定义相对)看起来像这样:

some_type function();