11. How does block actually come true? Try to see its implementation by converting the Block's code into a normal C language code.
To convert the OC code to the C language code, you can use a command compiled by clang:
This command can be used to rewrite the OC code in the specified file into C + + code (the main part is the normal C language code), the code can see how the block is implemented in the C + + language.
12, first write a simplest block, no return value and parameter list, execute it will output "Shayne Yeorg". The code is as follows:
Then using the 11 command to convert the file, you can get the file main.cpp. Main.cpp a lot of content, will be related to the code extracted as follows:
This is the main content of the block after the conversion.
13, the first time to see this code will feel a bit messy, after all, the use of variable names although there are regular but relatively long, in order to better understand the code, try to replace the main name with pseudo-code, as follows:
This time the content of this code is very clear:
(1), it first declares a struct to hold the infrastructure of the Block object (hereinafter Struct1), the struct is not a complete block, just a component, it mainly contains an Isa pointer and a function pointer funcptr;
(2), and then declare a specific function with a number (anonymous function), you can notice that the contents of the function is actually the source code in the block to execute the content;
(3), and then declare a struct to hold the block object size and other related information (hereinafter noted as STRUCT2), and define a concrete instance of this structure;
(4), with the above preparation, you can declare a complete block object of the struct, which consists of the above Struct1 and Struct2.
In addition, a constructor is declared for the complete block object's struct, which can be used to assign values not only to its internal struct2 but also to the Struct1 function member Funcptr.
(5), the last is the main function, in the main function, the first call to the complete block object of the struct's constructor defines a block object, the constructor uses the parameter is (2) the function and (3) the declaration of the Struct2 instance, The effect of defining block in the source code is reached.
After the block object is generated, the next step is to call the Struct1 function member Funcptr inside the Block object to achieve the effect of calling this block in the source code.
(6), this is the simplest block object of the complete implementation process.
14, from 13 of the implementation process can be analyzed:
(1), when defining the FUNCPTR function, it can be noted that it is a parameter, the parameter is a block full struct type variable __cself.
This is similar to the message sent, through the method call table to find the implementation of the corresponding method, passed to the method implementation of the two hidden parameters self and _cmd, in the method implementation through self and _cmd can get to the objc_messagesend () function of the two necessary parameters.
Similarly, in this case, the function can be accessed by __cself to the block itself that called the function.
This parameter is not used in the 13 example, it is only the simplest block, the following will be related to the use of this parameter situation;
(2), there is an Isa pointer inside the block, indicating that it is also an object. And when constructing this block, the pointer is pointed to the _nsconcretestackblock, which will be explained in detail below;
(3), block callback function, essentially through the call function implementation.
15, through 13 of the simple block example to understand the block's 3 main function points of the callback function of the essence, then the next step to explore another function point: intercept variables. Take a look at what blocks of blocks with intercept variables are converted to a normal C language. Write the following code:
This code defines two variables before the block is defined, and the two variables are used in the block. Executing this block will print out "Shayne Yeorg's shirt number is 10".
16. Rewrite the code using the Clang command, and the main parts extracted from the C + + code are as follows:
Where the declaration part of the __BLOCK_IMPL structure is omitted, this part is not changed.
17, analysis 16 of the Code:
(1), in the complete structure of block __MAIN_BLOCK_IMPL_0, two more members, the type of the member and the name and intercept of the variable name and Shirtnum, and its constructors also increased the initialization of the two member variables;
(2), then the __MAIN_BLOCK_FUNC_0 function is used to __cself, it through __cself can get to the corresponding __main_block_impl_0 object, and then can get two member variable name and Shirtnum value to use the ;
(3), in the main function, the construction of the block object, the definition of name and Shirtnum as a parameter passed in, so the next line of code calls FUNCPTR, you can get the value of the two variables by means of (2) method;
(4), so, the block intercept variable processing method is actually in its structure to increase and intercept variables of the same type of member variables, and then the value of the intercepted variable is saved in the member variable. This also explains why a variable that is intercepted by block also modifies its value without affecting the intercepted value in the block.
18, understand the block's callback and the function of intercepting variables after the implementation method, then look at the last function of block: Intercept variable variable.
Variables that can be modified in the block, when declared, need to enclose the __block modifier, which is very different from the normal variable, first of all, look at the fact that the __block variable is not related to block. Write the following code to see the difference:
After using the clang command to convert the code, the main parts are extracted as follows:
19, in 18, you can notice:
(1), attached __block variable, is converted to a global structure, the structure contains not only the value of the variable Blockvar, but also contains a __forwarding pointer, from the initialization of the code, this pointer to the BLOCKVAR structure itself;
(2), when modifying the value of the Blockvar variable, the value of the Blockvar member in the Blockvar struct is not modified directly, but is relocated to the BLOCKVAR structure by the __forwarding pointer in the struct (it is actually itself here). It then modifies the value of the Blockvar member found in the Blockvar struct body.
20, why modify the value of the variable modified to __block is not directly modified, to use the __forwarding pointer around a circle back to modify it?
This is because in some cases (as explained in detail), the block that intercepts the __block variable is copied from the stack to the heap, and the __block variable is copied to the heap, leaving the __block variable on the stack __ The forwarding pointer is set to point to the __block variable on the heap.
At this time, if the __block variable is used outside the block, although the variable is still stored on the stack, the __block variable on the heap can be accessed smoothly through the __forwarding pointer, and the same __ is accessed both inside and outside the block. The effect of the block variable.
21. After understanding the essence of the __block variable, we have a look at how the block of variable variable has been intercepted. Write the following code:
(Figure J intercept variable variable Block1)
This code modifies the value of the __block variable in the block, converting the code:
22. Analyze the 21 converted code:
(1), and 181, __block variable shirtnum is converted into a global structure __block_byref_shirtnum_0;
(2), similar to 16 of the interception of immutable variable code processing mode, block of the complete structure of the __MAIN_BLOCK_IMPL_0 will also add a __block_byref_shirtnum_0 struct type member Shirtnum, The constructor allows you to see that it is assigned a __forwarding member pointer to a __BLOCK_BYREF_SHIRTNUM_0 struct;
(3), in the __MAIN_BLOCK_FUNC_0 function, after obtaining the value of the Shirtnum member variable of the __main_block_impl_0 object through the __cself parameter, the shirtnum->__forwarding- >shirtnum such a way to modify its value;
(4), add the __main_block_copy_0 function and the __MAIN_BLOCK_DISPOSE_0 function, these functions are similar to the NSObject retain and release methods, but they are used to manage the Block object, Used when the block object is copied from the stack to the heap and discarded from the heap;
(5), in the main function, through the definition of __BLOCK_BYREF_SHIRTNUM_0 structure of the object, to achieve the definition of __block variable effect, this is also 181-like;
(6), this is the nature of the block that intercepted the variable variable.
Lattice 16: The Block I understand (2)