How does a Block capture the variables outside of its enclosing scope?

前端 未结 3 788
再見小時候
再見小時候 2020-12-01 09:45

I know that an Objective-C Block can capture and set the value of variables outside of its enclosing scope. How does it do that?

3条回答
  •  悲&欢浪女
    2020-12-01 10:29

    It's actually fairly straightforward and described in Clang's Block Implementation Spec, in the "Imported Variables" section.

    When the compiler encounters a Block like:

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

    it creates a literal structure that includes -- among other things -- two elements that are important here. There's a function pointer to the executable code in the Block, and a const field for each variable that's referred to inside the Block. Something like this:

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

    Notice that the invoke function will take a pointer to a struct of the kind that's being defined right here; that is, the Block passes itself in when executing its code. Thus, the code gets access to the members of the structure.

    Right after the declaration, the compiler creates a definition of the Block, which simply uses the referenced variables to initialize the correct fields in the 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. *
     };
    

    Then, inside the invoke function, references to the captured variables are made like any other member of a struct, the_block->numBalloons.

    The situation for object-type variables is a little more complicated, but the same principle applies.

提交回复
热议问题