【问题标题】:Passing block parameter that doesn't match signature传递与签名不匹配的块参数
【发布时间】:2013-08-09 17:06:00
【问题描述】:

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

【问题讨论】:

  • 我认为如果您将第一个更改为void (^MyBlockType)(void),您会收到投诉。我相信空的() 表示未指定的参数。
  • 是的,这让编译器抱怨它。你知道这是否记录在某个地方(如果有的话我没看到)?如果您想发表评论作为答案,我会接受。谢谢
  • 不确定——我从另一个问题的另一个答案中得到了这个信息 :) 让我看看。
  • 我发布了一个答案,但其他一些人也发布了:)
  • 我说如果你发帖我会接受你的回答,所以我会 :) +1 给其他答案,因为他们也有帮助。谢谢

标签: objective-c objective-c-blocks


【解决方案1】:

提供一个空参数规范,如

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 行为作为语言扩展来实现。

【讨论】:

    【解决方案2】:

    来自 Clang 块规范:

    支持可变参数...。 [variadic.c] 不带参数的块必须在参数列表中指定 void [voidarg.c]。正如 K&R 提供的那样,空参数列表并不表示未指定的参数列表。注意:为了方便起见,gcc 和 clang 都支持 K&R 样式。

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

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

    【讨论】:

      【解决方案3】:

      这是一个 C 的东西。具有空参数列表的函数或块原型意味着“函数(或块)采用您喜欢的任何参数”。如果你想表达这个块不应该有参数,你需要像这样明确地说:

      typedef void(^MyBlock)(void)
      

      这在很大程度上是 ANSI 之前没有函数原型并且所有函数声明(而不是定义)看起来像这样的历史:

      some_type function();
      

      【讨论】:

        猜你喜欢
        • 2023-03-26
        • 1970-01-01
        • 2017-10-05
        • 1970-01-01
        • 2021-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多