<span id="Label3"></p><span class="ico ico_type_Original" style="font-size: 15px;"><span class="ico ico_type_Original" style="font-size: 15px;"><span class="ico ico_type_Original"> </span></span></span><span class="link_title" style="font-size: 15px;"><span class="link_title" style="font-size: 15px;">probe into block implementation in iOS</span></span><span class="link_categories" style="font-size: 15px;"><span class="link_categories" style="font-size: 15px;"> </span></span><p class="p1"><p class="p1"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;">[0. Brief introduction of block]</span></span><p class="p2"><p class="p2"><span class="s1" style="font-size: 15px;">Block is an extension of the C language introduced by ios4.0+ and Mac OS X 10.6+ to implement the features of anonymous Functions.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">In the words of wikipedia, block is an attribute added by Apple Inc. for c, C + +, and objective-c, allowing these languages to create <span class="s1">closures</span> using the syntax of a class <span class="s1">lambda expression</span> .</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">In the Apple documentation, A block is a anonymous inline collection of code, and sometimes also called A "closure".</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">As for closures, I think Nanyi's explanation is concise: <span class="s2">closures are functions that can read other functions ' internal variables. </span></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">This explanation is also appropriate for block: a function defines a block that can access the internal variables of the Function.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">A simple block example is as Follows:</span></p></p><p class="p3"><p class="p3"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;"> <strong>[cpp]</strong> View Plaincopy</span></span><span style="font-size: 15px;"><span style="font-size:15px" , "><object id=" zeroclipboardmovie_1 " width=" height= " +" align="middle" bgcolor="# FFFFFF " data=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf " type=" application/ X-shockwave-flash "><param name=" src " value=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf "> <param name="loop" value="loop"><param name="menu" value="false"><param name="quality" value="best"><param Name="allowscriptaccess" value="always"><param name="allowfullscreen" value="false"><param name="pluginspage" value=" Http://www.macromedia.com/go/getflashplayer "><param name=" flashvars " value=" id=1&width=18&height=18 ">< param name= "wmode" value= "transparent" > </object> </span></span> <ol class="dp-cpp" start="1"> <ol class="dp-cpp" start="1"> <li class="alt"><span class="datatypes" style="font-size: 15px;">int (^maxblock) (<span class="datatypes">int, int <span class="datatypes">) = ^ (<span class="datatypes">int x, <span class="datatypes">int Y) { <span class="keyword">return x > Y x:y;}; </span></span></span></span></span></span></li> </ol> </ol><p><p><span style="font-size: 15px;">If you write with a Python lambda expression, it can be written as Follows:</span></p></p><p class="p3"><p class="p3"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;"> <strong>[python]</strong> View Plaincopy</span></span><span style="font-size: 15px;"><span style="font-size:15px" , "><object id=" zeroclipboardmovie_2 " width=" height= " +" align="middle" bgcolor="# FFFFFF " data=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf " type=" application/ X-shockwave-flash "><param name=" src " value=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf "> <param name="loop" value="loop"><param name="menu" value="false"><param name="quality" value="best"><param Name="allowscriptaccess" value="always"><param name="allowfullscreen" value="false"><param name="pluginspage" value=" Http://www.macromedia.com/go/getflashplayer "><param name=" flashvars " value=" id=2&width=18&height=18 ">< param name= "wmode" value= "transparent" > </object> </span></span> <ol class="dp-py" start="1"> <ol class="dp-py" start="1"> <li class="alt"><span style="font-size: 15px;">f = <span class="keyword">Lambda x, y:x <span class="keyword">if x > y <span class="keyword">else y</span> </span> </span></span></li> </ol> </ol><p><p><span style="font-size: 15px;">however, because of the language characteristics of Python itself, in the function body defined by def, it is natural to use DEF statements to define inline functions, because these functions are essentially objects.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">If you use BNF to represent the context-independent grammar of a block, it is roughly the following:</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;"> <strong>[cpp]</strong> View Plaincopy</span></span><span style="font-size: 15px;"><span style="font-size:15px" , "><object id=" zeroclipboardmovie_3 " width=" height= " +" align="middle" bgcolor="# FFFFFF " data=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf " type=" application/ X-shockwave-flash "><param name=" src " value=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf "> <param name="loop" value="loop"><param name="menu" value="false"><param name="quality" value="best"><param Name="allowscriptaccess" value="always"><param name="allowfullscreen" value="false"><param name="pluginspage" value=" Http://www.macromedia.com/go/getflashplayer "><param name=" flashvars " value=" id=3&width=18&height=18 ">< param name= "wmode" value= "transparent" > </object> </span></span> <ol class="dp-cpp" start="1"> <ol class="dp-cpp" start="1"> <li class="alt"><span style="font-size: 15px;">block_expression:: = ^ Block_declare block_statement</span></li> <li><span style="font-size: 15px;">block_declare:: = Block_return_type block_argument_list</span></li> <li class="alt"><span style="font-size: 15px;">block_return_type:: = Return_type | Empty</span></li> <li><span style="font-size: 15px;">block_argument_list:: = Argument_list | Empty</span></li> </ol> </ol><p><p><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;">[1. Why block]</span></span><p class="p2"><p class="p2"><span style="font-size: 15px;">In addition to being able to define parameter lists, return types, blocks can also obtain state (such as local variables) within the lexical scope that is defined, and can modify these states under certain conditions, such as using the <strong>__block</strong> variable. In addition, these modifiable states are shared among multiple blocks within the same lexical scope, and can continue to share or modify these states, even if the lexical scope (such as stack expansion, out of Scope) is Out.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">In general, blocks are encapsulated in short snippets of code that are used as work units, often for concurrent tasks, traversal, and Callbacks.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">For example, we can do something when we traverse the nsarray:</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;"> <strong>[cpp]</strong> View Plaincopy</span></span><span style="font-size: 15px;"><span style="font-size:15px" , "><object id=" zeroclipboardmovie_4 " width=" height= " +" align="middle" bgcolor="# FFFFFF " data=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf " type=" application/ X-shockwave-flash "><param name=" src " value=" http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf "> <param name="loop" value="loop"><param name="menu" value="false"><param name="quality" value="best"><param Name="allowscriptaccess" value="always"><param name="allowfullscreen" value="false"><param name="pluginspage" value=" Http://www.macromedia.com/go/getflashplayer "><param name=" flashvars " value=" id=4&width=18&height=18 ">< param name= "wmode" value= "transparent" > </object> </span></span> <ol class="dp-cpp" start="1"> <ol class="dp-cpp" start="1"> <li class="alt"><span style="font-size: 15px;">-(<span class="keyword">void) enumerateobjectsusingblock: (<span class="keyword">void (^) (id obj, nsuinteger idx, <span class="datatypes">BOOL *stop)) block; </span></span></span></span></li> </ol> </ol><p><p><span style="font-size: 15px;">If stop is set to yes, it jumps out of the loop and does not continue to Traverse.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">In many frameworks, block is increasingly used as a <span class="s4">callback function instead of the traditional callback Method. </span></span></p></p> <ul class="ul1"> <ul class="ul1"> <li class="li1"><span style="font-size: 15px;">Using block as a callback function allows programmers to write code more smoothly, without running halfway to another place to write a callback function, and sometimes to consider where the callback function is Appropriate. With block, you can write the subsequent processing code directly when the function is called, passing it as a parameter for the callback at the end of its task Execution.</span></li> <li class="li1"><span style="font-size: 15px;">Another benefit is that block is used as a callback to directly access local Variables. For example, I want to modify the name of a user in a batch of users, and then update the corresponding User's cell UI with a callback after the modification is Complete. At this time I need to know the corresponding user cell index, if the use of traditional callback, you need to bring the index to the past, callback and return it back; the index of the current action cell is recorded by an external scope (this limits the name of only one user at a Time) ; traverse to find the corresponding user. With block, you can access the Cell's index directly.</span></li> </ul> </ul><p class="p1"><p class="p1"><span class="s1" style="font-size: 15px;">This document mentions several applications of Block:</span></p></p> <ul class="ul1"> <ul class="ul1"> <li class="li1"><span style="font-size: 15px;">Callback processing at task completion</span></li> <li class="li1"><span style="font-size: 15px;">Message Listener Callback Processing</span></li> <li class="li1"><span style="font-size: 15px;">Error callback Handling</span></li> <li class="li1"><span style="font-size: 15px;">Enumeration callback</span></li> <li class="li1"><span style="font-size: 15px;">View animations, Transformations</span></li> <li class="li1"><span style="font-size: 15px;">Sort</span></li> </ul> </ul><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;">[2. about __block_impl]</span></span><p class="p2"><p class="p2"><span style="font-size: 15px;">Clang provides an option for intermediate code presentation to further understand the principle of block.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">Take a very simple code example:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">Compile using THE-REWRITE-OBJC option:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">To get a copy of the Block0.cpp file, you can see the following code snippet in this document:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">It can be seen from the naming that this is the implementation of block and that block is implemented in the <span class="s4">front-end of the clang compiler to generate C intermediate Code. Many languages can implement only the compiler front end, generate C intermediate code, and then take advantage of many of the existing C-compiler backend. </span></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">As you can see from the members of the struct, Flags and reserved can be skipped first, and the<strong>ISA</strong> pointer indicates that the block can be a nsobject, and the <strong>funcptr</strong> pointer is clearly the corresponding function pointer of the BLOCK.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">thus, The mystery of block was Unveiled.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">But where is the block-related variable? The above mentioned block can capture the state of the lexical scope (or the outer context, scope), even if it is out of the range, you can still modify these States. How is this done?</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;">[3. Implementation of a simple block]</span></span><p class="p2"><p class="p2"><span style="font-size: 15px;">Let's look at a block that only outputs one sentence.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">Generate the intermediate code to get the fragment as Follows:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">The first appearance of the structure is <strong>__main_block_impl_0</strong>, it can be seen according to the <span class="s4">function (main Function) and the occurrence of a <span class="s4">sequence (No. 0) named. If it is a global block, it is named according to the variable name and the occurrence sequence. __MAIN_BLOCK_IMPL_0 contains two member variables and a constructor, member variables are __block_impl struct and descriptive information desc, followed by initialization of block type information and function pointers in the Constructor. </span></span></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">The next occurrence is the <strong>__main_block_func_0</strong> function, which is the block corresponding function body. The function accepts a <strong>__cself</strong> parameter, which is the corresponding block itself.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">The following is the <strong>__main_block_desc_0</strong> structure, where the more valuable information is the block Size.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">finally, the creation and invocation of the block in the main function shows <strong></strong> that the block is <span class="s4">called a function that takes the block itself as a parameter, which corresponds to the Block's Execution. </span></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">here, The block type is represented by <strong>_nsconcretestackblock</strong> , indicating that the block is in the STACK. In the same vein, there are <strong>_nsconcretemallocblock</strong> and <strong>_nsconcreteglobalblock</strong>.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">Since block is also a nsobject, we can do retain operations on it. however, when the block is passed as a callback function to the underlying framework, the underlying framework needs to <strong>copy</strong> it. For example, If the callback block is used as a property, you cannot use retain, but copy. We usually write blocks in the stack, and when we need callbacks, the callback block is not already in the stack, and using the copy property, you can put the block into the heap. or use <strong>block_copy</strong>() and <strong>block_release</strong>().</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;">[4. Capture Local variable]</span></span><p class="p2"><p class="p2"><span style="font-size: 15px;">Let's look at a block that accesses local Variables.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">Generate the intermediate code to get the fragment as Follows:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">It can be seen that the block structure __main_block_impl_0 a <strong>member variable</strong> <span class="s4"> <strong>i</strong>, used to store the local variable i (value 1024), and at this point can see <span class="s4"> <strong>__cself </strong>the function of the parameter, similar to this in C + + and the self of Objective-c. </span></span></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">If we try to modify the local variable i, we get the following error:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">The error message is verbose, telling us that the variable is not assignable and reminds us to use the <strong>__block</strong> type Identifier.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">Why can't I assign a value to the variable i?</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">Because the local variable i and the function __main_block_func_0 in the main function are <span class="s2">not in the same scope, only the value is passed during the Call. of course, in the above code, we can use pointers to implement local variable Modification. This is due to the fact that the main function stack has not been completed while calling __main_block_func_0, and the<span class="s2">variable i is still in the STACK. however, in many cases, the block is passed as a parameter for subsequent callbacks to Execute. Usually in these cases, when the block is executed, <span class="s2">the function stack where the definition is defined is already expanded, and the local variable is no longer in the stack (<span class="s4">where is the block at this time?). ), and then use the pointer to access it??。 </span></span></span></span></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">therefore, it is reasonable to disallow block modification for local variables of auto Type.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;">[5. Modify static local variable]</span></span><p class="p2"><p class="p2"><span style="font-size: 15px;">We can also infer how static local variables are modified in the block execution Body-through Pointers.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">Because <span class="s2">static local variables exist in the data segment, there is no risk of an illegal fetch after stack Expansion. </span></span></p></p><p class="p4"><p class="p4"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">The difference between the above intermediate code fragment and the previous fragment is mainly that the address of <strong>I</strong>is passed in the main function (<span class="s4"><strong>&i</strong><strong>)</strong>, and the __main_block_impl_ 0 The member I in the struct becomes the pointer type (<span class="s4"><strong>int *</strong>). </span></span></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">The value is then modified by the pointer when the block is Executed.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">of course, global variables, static global variables can be modified in the block execution Body. More precisely, The block can modify the variables within its scope when it is called (this is __main_block_func_0). For example, when a block is a member variable, it can also access other member variables in the same object.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><span style="font-size: 15px;"><span style="font-size: 15px;">[6. Implementation of __block variable]</span></span><p class="p2"><p class="p2"><span style="font-size: 15px;">so, How does the __block type variable support the modification?</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">We add the __block indicator to the INT type variable so that the variable I can be modified in the block function body.</span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">Then look at the middle code, there will be a lot more information. The first is the corresponding structure of the __block variable:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">The first member of the <span class="s4"> <strong>__isa</strong> Pointer can also know that <strong>__block_byref_i_0</strong> can also be nsobject.</span></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">The second member <span class="s4"> <strong>__forwarding</strong> points to himself, why point to Himself? There is no point pointing to yourself, only to say that sometimes you need to point to another __block_byref_i_0 Structure.</span></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">The last member is the target storage variable I.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">At this point, the __MAIN_BLOCK_IMPL_0 structure is as follows:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">The member variable I of __MAIN_BLOCK_IMPL_0 becomes the <span class="s4"> <strong>__block_byref_i_0 *</strong> type.</span></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">The corresponding function __main_block_func_0 is as Follows:</span></p></p><p class="p4"><p class="p4"><span style="font-size: 15px;"></span></p></p><p class="p1"><p class="p1"><span class="s4" style="font-size: 15px;">The highlight is the __BLOCK_BYREF_I_0 pointer type variable i, which operates another member variable through its member variable <strong>__forwarding</strong> pointer. :-)</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">and the main function is as Follows:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">With this seemingly complex change, we can modify the value of the variable I. But the problem also exists: the __BLOCK_BYREF_I_0 type variable <span class="s4"> <strong>i</strong> is still on the stack, when the Block is executed by the callback, the stack of the variable i is already expanded, what should I do?</span></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">At this critical moment, __main_block_desc_0 stood out:</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">At this point, __main_block_desc_0 has two more member Functions: copy and dispose, respectively, pointing to <span class="s4"> <strong>__main_block_copy_0</strong> and <span class="s4"> <strong>__main_block_dispose_ 0</strong>. </span></span></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">When the block is copied onto the heap from the stack, it calls __main_block_copy_0 to copy the member variable I of the __block type from the stack to the heap, and when the block is released, it calls __main_block_dispose_0 to release _ The member variable I of the _block type.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">One will be on the stack, one on the heap, then what if the variable is manipulated on the stack and on the heap?</span></p></p><p class="p3"><p class="p3"><span class="s5" style="font-size: 15px;">At this point, the role of __forwarding is manifested: when a __block variable is copied from the stack onto the heap, the __forwarding pointer in the __BLOCK_BYREF_I_0 struct on the stack also points to the structure on the heap <span class="s5">. </span></span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;"></span></p></p><p class="p1"><p class="p1"><span style="font-size: 15px;">/* ---------------------------------------------------------------------------------------------------- */</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">Would like to continue to write, the results found that the article is a bit long. Come here First.</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">Original Link: http://blog.csdn.net/jasonblog/article/details/7756763</span></p></p><p class="p2"><p class="p2"><span style="font-size: 15px;">Jason Lee @ Hangzhou</span></p></p><p><p>Probe into block implementation in iOS</p></p></span>
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.
A Free Trial That Lets You Build Big!
Start building with 50+ products and up to 12 months usage for Elastic Compute Service