15

私は、Objective-C ブロックがそれを囲むスコープ外の変数の値を取得して設定できることを知っています。それはどのように行うのですか?

4

3 に答える 3

26

これは実際にはかなり簡単で、Clang のブロック実装仕様の「インポートされた変数」セクションで説明されています。

コンパイラが次のようなブロックに遭遇した場合:

^{ if( numBalloons > numClowns) abort(); }

とりわけ、ここで重要な 2 つの要素を含む文字通りの構造を作成します。ブロック内の実行可能コードへの関数ポインターと、ブロックconst内で参照される各変数のフィールドがあります。このようなもの:

struct __block_literal_1 {
    /* other fields */
    void (*invoke)(struct __block_literal_1 *);
    /* ... */
    const int numBalloons;
    const int numClowns;
};

invokeこの関数は、ここで定義されている種類の構造体へのポインターを取ることに注意してください。つまり、ブロックはそのコードを実行するときに自分自身を渡します。したがって、コードは構造体のメンバーにアクセスできます。

宣言の直後に、コンパイラはブロックの定義を作成します。これは、参照された変数を使用して、.xml ファイル内の正しいフィールドを初期化するだけですstruct

struct __block_literal_1 __block_literal_1 = {
    /* Other fields */
    __block_invoke_2,  /* This function was also created by the compiler. */
    /* ... */
    numBalloons,  /* These two are the exact same variables as */ 
    numClowns     /* those referred to in the Block literal that you wrote. *
 };

次に、invoke関数内で、キャプチャされた変数への参照が、構造体の他のメンバーと同様に作成されますthe_block->numBalloons

オブジェクト型変数の状況はもう少し複雑ですが、同じ原則が適用されます。

于 2013-07-23T19:17:07.843 に答える
0

基本的に、ブロック「オブジェクト」には、キャプチャされたローカル変数ごとに、ブロック オブジェクト内の変数 (ブロック オブジェクトの「インスタンス変数」など) が含まれます。(Josh Caswell の回答は、実装方法の詳細を提供します。) ブロックが作成されると、その時点でキャプチャされた各ローカル変数の値が、ブロック内の対応する変数にコピーされます。変数がブロック内で使用される場合は常に、代わりにブロック内でこの変数が使用されます。

于 2013-07-24T01:06:00.953 に答える