ブロックを含む配列があり、それらすべてが指定された数の引数を期待していることを表明する必要があるとしましょう。
これをプログラムで見つける方法はありますか?
ブロックを含む配列があり、それらすべてが指定された数の引数を期待していることを表明する必要があるとしましょう。
これをプログラムで見つける方法はありますか?
これは、Clangの最近のバージョンでは確かに可能です。
Apple ABI for Blocksは非公開ですが、公開されています。そのドキュメントは、コンパイラがBlockオブジェクトに使用するレイアウトを示しているため、その情報をヘッダーファイルに複製し、それを使用してBlockのコンポーネントにアクセスできます。
Mike AshのMABlockForwardingプロジェクトは、まさにそれを実行します(記事も参照)。このファイルの上部にあるものの多くは、ABIドキュメントからのコピーアンドペーストです。私たちが興味を持っている彼が作成したものは、BlockSig()
関数です。
static const char *BlockSig(id blockObj)
{
struct Block *block = (__bridge void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
assert(block->flags & BLOCK_HAS_SIGNATURE);
int index = 0;
if(block->flags & BLOCK_HAS_COPY_DISPOSE)
index += 2;
return descriptor->rest[index];
}
これは(それを持っているブロック(最近のClangですべて実行します))、ブロックの戻り値と引数の型を記述する文字列をエンコードする型を返します。そこから、NSMethodSignature
オブジェクトを作成し、そのオブジェクトを要求できnumberOfArguments
ます。
NSString * (^block)(int, NSArray *) = ^NSString * (int i, NSArray * a){
return @"Oh, yeah!";
};
const char * types = BlockSig(block);
NSMethodSignature * sig = [NSMethodSignature signatureWithObjCTypes:types];
[sig numberOfArguments];
ブロック自体の非表示の引数が含まれているため、結果は3になります(ブロックは非表示の_cmd
引数を使用しないか、4になります)。
答えはできません。これに関するMikeAshのページのコメントを参照してください。
ここにあなたを送るIntropectionを検索してください
それで、あなたの本当の問題は何ですか?引数を適切に構成すると、システムが適切に機能することを保証できます。たとえば、C ++が引数のデフォルト値で行うことを実行し、各ブロックを引数の最大数をとる型にキャストし、常にその数の項目をスタックにプッシュすることができます。または、常に最初の引数をスタックにプッシュする引数の数にすることもできます。数値/ポインターではなくオブジェクトをプッシュする場合、rブロックは各引数のクラスを調べて動的に適応できます。