8

私はブロックベースの API を使用しており、メソッドが期待していた typedef パラメーターと一致しない署名を持つブロック パラメーターを渡していたシナリオに出くわしました。驚いたことに、コンパイラはこれを気にしていないようで、アプリはクラッシュしませんでした。これは予想される動作ですか?例:

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");
}
4

3 に答える 3

9

次のように空の引数指定を提供する

typedef void(^MyBlock)();

「指定されていない」引数を意味します。したがって、2 つのタイプは、書かれているように互換性があります。最初の宣言を次のように変更

typedef void(^MyBlock)(void);

ブロックが引数を取らず、エラーが発生することを指定します。

K&R C は、空の引数リストが「未指定」を意味すると指定しています。C ブロック仕様では、これはブロック型宣言には当てはまらないと述べています ( http://clang.llvm.org/docs/BlockLanguageSpec.html#block-variable-declarationsを参照)、GCC と Clang の両方が K&R 動作を言語拡張。

于 2013-08-09T17:29:18.973 に答える
4

Clang Blocks 仕様から:

可変引数...がサポートされています。[variadic.c] 引数を取らないブロックは、引数リスト[voidarg.c] に void を指定する必要があります。K&R が提供するように、空のパラメーター リストは未指定の引数リストを表していません。注: gcc と clang はどちらも便利なように K&R スタイルをサポートしています。

基本的に、これは C 構文の古い癖です。昔は、C 関数宣言の構文はかなり異なり、空の括弧は、関数に任意の数の引数を渡すことができることを示していました。下位互換性のために、コンパイラは通常、古いスタイルの関数宣言構文を許可しています。そして何らかの理由で、Apple は、実際には GCC と Clang の両方のブロックで使用できるようにする一方で、ブロック標準でこの構文を同時に拒否することを決定しました。

要するに、ブロックが引数を取らないことを宣言するには、次のように明示的に入力する必要があります。void(^MyBlock)(void)

于 2013-08-09T17:24:11.800 に答える
3

これはCのことです。空の引数リストを持つ関数またはブロックのプロトタイプは、「関数 (またはブロック) が任意の引数を取る」ことを意味します。ブロックに引数がないことを伝えたい場合は、次のように明示的に言う必要があります。

typedef void(^MyBlock)(void)

これは主に、関数プロトタイプがなく、すべての関数宣言 (定義ではなく) が次のように見えた ANSI の前の時代からの歴史です。

some_type function();
于 2013-08-09T17:23:15.653 に答える