Block Storage area First, you need to introduce three nouns: _nsconcretstackblock _nsconcretglobalblock
_nsconcretmallocblock
As their names show, there are three ways to store blocks: Stack, Global, heap. The value of ISA in the Block object is one of the above, and the following starts to indicate which block is stored in the stack, heap, global. ------------"point 1": Global block------------The block defined outside the function is a block of the global type defined within the function, but does not capture any automatic variables, it is also global. such as the following code
[OBJC]View Plaincopy
- typedef INT (^blk_t) (int);
- For (...) {
- blk_t blk = ^ (int count) {return count;};
- }
Although, this block is within the loop, but the address of the blk is always constant. Indicates that this block is in the global segment.Note: For blocks that do not capture automatic variables, although _nsconcretstackblock is still shown in the converted code with Clang REWRITE-OBJC, this is not actually the case. You can prove that the block of this type is global. Xcode5.1.1 Debug Results
whether arc or not, the console output is <__nsglobalblock__: 0x10000f280> This is probably the compiler's optimization, I guess, no proof. So it is inaccurate to use Clang's-REWRITE-OBJC.
------------"point 2": Stack block--------------This situation, under the non-arc is not compiled, under the arc can be compiled
[OBJC]View Plaincopy
- typedef VOID (^block_t) ();
- -(block_t) returnblock{
- __block int add=10;
- return ^{printf ("add=%d\n", ++add);
- }
This is because the block captures the Add auto variable on the stack, when add has become a struct, and the block has a pointer to the struct body. That is, if a block is returned, a pointer to the local variable is returned. And this is exactly what the compiler has decided.It can be compiled under ARC because ARC uses autorelease. Again a scene:
[OBJC]View Plaincopy
- -(block_t) returnblock{
- __block int add=10;
- block_t blk_h =^{printf ("add=%d\n", ++add);};
- return blk_h;
- }
- block_t BB = [self returnblock];
- BB ();
This code, just used an automatic block variable, can be compiled, but caused the program to crash.
If you add copy when you return to block, you can output the correct value 11
------------"Point 3": Block on the heap----------------sometimes we need to call block's copy function to copy the block to the heap. Look at the following code:
[OBJC]View Plaincopy
- -(ID) getblockarray{
- int val =10;
- return [Nsarray arraywithobjects:
- ^{nslog (@ "blk0:%d", Val);},
- ^{nslog (@ "blk1:%d", Val);},nil];
- }
- ID obj = Getblockarray ();
- typedef VOID (^blk_t) (void);
- blk_t blk = (blk_t) {obj Objectatindex:0};
- Blk ();
This code will be an exception on the last line blk () because the block in the array is on the stack. Because Val is on the stack. The workaround is to call the Copy method. In this scenario, ARC does not add a copy for you, because arc is unsure and takes a conservative approach: do not add copy. so the arc will also exit abnormally. ---------------------the use of "point 4" copy-----------------------------------no matter where the block is configured, copying with the copy method does not cause any problems.in the ARC environment, if you are unsure if you want to copy the block, copy it. ARC will sweep the battlefield. "Note": Call copy on the stack then copy to the heap on the global block call copy nothing to call the block reference count on the heap add------------------"Challenges to objective-c advanced programming"---------- -------------author using xcode 5.1.1 IOS SDK 7.1 compilation discovery: Not as described in the book Objective-c Advanced Programming,-REWRITE-OBJC This command conversion of intermediate code, not reliable.Block has a huge difference between arc and non-arc: The following two methods are used to verify:
1. Through Xcode debug results , drawings
2. Pass the address of the variableThe int Val is definitely on the stack, and I saved the Val address to see if the block was changed before and after the call. The output of the consistent description is on the stack, and the inconsistent description is on the heap. "The first method", the most intuitive. The code is as simple as this one. Block captures the variable val (Whether Val is __block or not)
[OBJC]View Plaincopy
- -(void) stackorheap{
- __block int val =10;
- Blkt1 s= ^{
- return ++val;};
- S ();
- Blkt1 h = [s copy];
- H ();
- }
Under non-ARC and arc, the debug results are as follows:you can see the non-arc next is the stack one is malloc. It's all malloc under Arc .
"Second method", declares a local variable pointer. by pointers
[OBJC]View Plaincopy
- typedef INT (^blkt1) (void);
- -(void) stackorheap{
- __block int val =10;
- intint *valptr = &val; Use the int pointer to detect whether the block is on the stack or on the heap
- Blkt1 s= ^{
- NSLog (@ "Val_block =%d", ++val);
- return Val;};
- S ();
- NSLog (@ "Valpointer =%d", *valptr);
- }
Under Arc >>>>>>>>>>> The block is generated directly onto the heap. Look at log:Val_block = Valpointer = TenUnder non-Arc >>>>>>>>> The block is still on the stack. Look at log:Val_block = one valpointer = One
The result after the call to copy:
[OBJC]View Plaincopy
- -(void) stackorheap{
- __block int val =10;
- intint *valptr = &val; Use the int pointer to detect whether the block is on the stack or on the heap
- Blkt1 s= ^{
- NSLog (@ "Val_block =%d", ++val);
- return Val;};
- Blkt1 h = [s copy];
- H ();
- NSLog (@ "Valpointer =%d", *valptr);
- }
Under Arc >>>>>>>>>>> no effect. Val_block = Valpointer = 10
Under non-Arc >>>>>>>>> did replicate to the heap. Val_block = Valpointer = Ten
----------------"Summary"-----------------expressed in this form. Capture variables include just reading the variables and __block the write variable in two ways (in fact the result is the same)
under Arc: There seems to be no block on the stack, either global or on the heapunder non-arc: There are three forms of this stack, global, heap.
Block Storage Area