我正在使用基于块的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");
}
答案 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();