4

私の iOS アプリケーションでは、お互いをパラメーターとして受け取る 2 つのブロック タイプを定義したいと考えています。

typedef void (^BlockA)(BlockB b);
typedef void (^BlockB)(BlockA a);

これはコンパイルに失敗し、最初の typedef で '不明な型名 BlockB が発生します (これは理にかなっています)。

次のようなタイプを定義する回避策があります。

typedef void (^BlockA)(id);
typedef void (^BlockB)(BlockA a);

次に、BlockA 定義内の BlockB 型にキャスト バックしますが、型の安全性が犠牲になります。

typedef を使用しないことも検討しましたが、これにより、展開されたブロック定義が無限にネストされます。

前方宣言を使用して構造体の循環依存を解決する方法は知っていますが、ブロックでこれを行う方法がわかりません。

循環依存関係の解決策がない場合、BlockA へのパラメーターをジェネリックではなく任意の Block 型に制限できる方法はありますか?idこれにより、ある程度の型安全性が得られます。

4

1 に答える 1

2

typedef「実際の」タイプを定義しません。基本的には、使用されるすべての場所に展開されるマクロのようなものです。そのため、typedefsを再帰的にすることはできません。

それについて考える別の方法は、typedefsは決して必要ではないということです-あなたはいつでもコードの任意の部分を.で取り、typedefそれのすべての出現を基礎となる型に置き換えることができます(それはあなたがコンパイルするときにコンパイラが行うことです)、そしてそれは常に機能し、完全に同等です。それについて考えてください-あなたはそれなしでどのようにそれをしtypedefますか?できません。したがって、どちらでもそれを行うことはできませんtypedef

それを行う唯一の方法は次のとおりです。id引数の型として使用して、実行しているように型を消去します。structまたは、またはクラスのような「実際の」タイプ内にブロックをカプセル化します。ただし、後者の方法で行う場合は、ブロックを構造体またはクラスに明示的に配置し、そこからブロックを抽出する必要があるため、コードが混乱します。また、struct構造体はスカラーCタイプであり、ブロックでキャプチャする必要がある場合、構造体内のオブジェクトを自動的にメモリ管理しないため、危険です。クラスに関しては、ラッピングクラスの定義は非常に冗長であり、これを使用すると、ラッピングするすべてのブロックに無関係なダミーオブジェクトが割り当てられます。

私の意見では、idあなたが使用しているように使用することは問題なく、最もクリーンな方法です。ただし、そのブロックを別の内部ブロックによってキャプチャされるように渡す必要がある場合はid、キャプチャのセマンティクスがブロックと他のオブジェクトタイプ(ブロック)で異なるため、キャプチャする前にブロックタイプにキャストバックする必要があることに注意してください。他のオブジェクトは保持されますが、コピーされます)。一番早い場所でブロックタイプにキャストバックするだけでうまくいきます。

于 2012-10-16T18:40:54.387 に答える