Then "Block intercepted automatic variables to achieve the realization of the internal __block modifier" We continue to explore Block
Leaving questions
- 1
__Block_byref_i_0 *__forwarding
; this pointer is pointing to itself what the hell, what role, when to use? - 2, Desc_0 structure in the extra
void (*copy) void (*dispose)
two methods What is the role, when to use?
Block essence of variables and __block
name | substance |
---|---|
Block | The stack structure example of Block |
__block variable | Examples of body structures on the stack variables __block |
Block type
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
__Block_byref_i_0 *i; // by ref
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, __Block_byref_i_0 *_i, int flags=0) : i(_i->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
We all know isa pointer is a pointer to its class, so impl.isa = &_NSConcreteStackBlock;
it indicates that the Block is _NSConcreteStackBlock
type. Namely Block on the stack.
Of course
class | Storage domain object Set |
---|---|
_NSConcreteStackBlock | Stack |
_NSConcreteGlobalBlock | Data area of the program (.data region) |
_NSConcreteMallocBlock | stack |
Under what circumstances is _NSConcreteGlobalBlock type of Block
By name, global (global) we create a global Block, look at his results compiled
#import "ViewController.h"
//全局的Block
void (^blk)(void) = ^{NSLog(@"123");};
typedef void(^WxsBlock) ();
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
blk();
}
@end
Compiled
struct __blk_block_impl_0 {
struct __block_impl impl;
struct __blk_block_desc_0* Desc;
__blk_block_impl_0(void *fp, struct __blk_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteGlobalBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __blk_block_func_0(struct __blk_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_t9_g3xrsv653kz2gr7tmgwfbfvh0000gn_T_ViewController_fbc035_mi_0);}
static struct __blk_block_desc_0 {
size_t reserved;
size_t Block_size;
} __blk_block_desc_0_DATA = { 0, sizeof(struct __blk_block_impl_0)};
static __blk_block_impl_0 __global_blk_block_impl_0((void *)__blk_block_func_0, &__blk_block_desc_0_DATA);
void (*blk)(void) = ((void (*)())&__global_blk_block_impl_0)
we discoverimpl.isa = &_NSConcreteGlobalBlock;
We again from block as normal local variables, function return value, when the type of function parameters see it
Automatic variable taken
@property(nonatomic, assign) blk_t blockAssgin;
@property(nonatomic, strong) blk_t blockStrong;
@property(nonatomic, copy) blk_t blockCopy;
blk_t getBlk_t(int i) {
blk_t block4 = ^(int count){return count*i;};
NSLog(@"作为函数返回值,有自动变量截取---%@",block4);
return block4;
}
{
//作为普通变量, 有自动变量截取
blk_t block1 = ^(int count) {
return count * value;
};
NSLog(@"作为普通变量, 有自动变量截取---%@",block1);
//作为assign类型成员变量 ,有自动变量截取
self.blockAssgin = ^(int count) {
return count * value;
};
NSLog(@"作为assign类型成员变量 ,有自动变量截取---%@",self.blockAssgin);
//作为strong类型成员变量 ,有自动变量截取
self.blockStrong = ^(int count) {
return count * value;
};
NSLog(@"作为strong类型成员变量 ,有自动变量截取---%@",self.blockStrong);
//作为copy类型成员变量 , 有自动变量截取
self.blockCopy = ^(int count) {
return count * value;
};
NSLog(@"作为copy类型成员变量 , 有自动变量截取---%@",self.blockCopy);
//作为函数返回值,有自动变量截取
getBlk_t(value);
//作为函数参数,有自动变量截取
[self actionBlock:^int(int i) {
return i*value;
}];
}
- (void)actionBlock:(blk_t)block {
//作为函数参数,无自动变量截取
NSLog(@"作为函数参数,有自动变量截取---%@",block);
block(1);
}
NSLog 日志:
Block[47786:5956467] 作为普通变量,有自动变量截取---<__NSMallocBlock__: 0x60000024c9c0>
Block[47786:5956467] 作为assign类型成员变量,有自动变量截取---<__NSStackBlock__: 0x7fff5fbc39e0>
Block[47786:5956467] 作为strong类型成员变量,有自动变量截取---<__NSMallocBlock__: 0x608000056110>
Block[47786:5956467] 作为copy类型成员变量,有自动变量截取---<__NSMallocBlock__: 0x608000056620>
Block[47786:5956467] 作为函数返回值,有自动变量截取---<__NSMallocBlock__: 0x6080000565c0>
Block[47786:5956467] 作为函数参数,有自动变量截取---<__NSStackBlock__: 0x7fff5fbc3968>
However, the results compiled by the clang out, they all are all equally impl.isa = &_NSConcreteStackBlock;
shocked not a surprise? Meaning no accident?
No automatic variable taken
{
//作为返回值,无自动变量截取
blk_t blockt = getBlk_t();
NSLog(@"作为返回值,无自动变量截取blockt---%@",blockt);
//作为普通变量,无自动变量截取,此处尝试了@property(strong,assgin,copy)这三种情况,是相同的结果
self.blocktest = ^(int count){return count;};
NSLog(@"作为普通变量,无自动变量截取----%@",self.blocktest);
//作为函数参数,无自动变量截取
[self actionBlock:^int(int i) {
NSLog(@"%d",i);
return i;
}];
}
- (void)actionBlock:(blk_t)block {
//作为函数参数,无自动变量截取
NSLog(@"作为函数参数,无自动变量截取---%@",block);
block(1);
}
打印结果
Block[47535:5919554] 作为返回值,无自动变量截取blockt---<__NSGlobalBlock__: 0x1039fd0f0>
Block[47535:5919554] 作为普通变量,无自动变量截取----<__NSGlobalBlock__: 0x1039fd150>
Block[47535:5919554] 作为函数参数,无自动变量截取---<__NSGlobalBlock__: 0x1039fd190>
全部是GlobalBlock
However, the results compiled by the clang out, they all are all equally impl.isa = &_NSConcreteStackBlock;
shocked not a surprise? Meaning no accident?
By compiling clang only see in ARC Block type the static case (static code statement), I feel only as a reference, there is still running.
So we can print the results of the NSLog briefly summarize:
Block type | Whether the automatic variable interception | Usage |
---|---|---|
_NSConcreteGlobalBlock | Have | As a global variable declaration and initialization |
no | All cases | |
NSStackBlock | Have | assgin member variable of type |
As a function parameter | ||
no | no | |
_NSConcreteMallocBlock | Have | As an ordinary local variables |
As a member variable of type copy | ||
As a member variable of the type of strong | ||
As a function return value | ||
no | no |
Why _NSConcreteGlobalBlock type Block to be set in the data area?
Because in place using global variables will not be automatically intercepted variables. Because it is a beginning it has been defined. There is no "variable", so its execution is fixed at any time and run-time environment does not depend on the operation of this type is only one global can not only save space and good management. So on the global static data area of the region better and better.
By contrast clang compiled and summarized the NSLog
By clang compiled results, except when the global variable declaration and creation of the block is compiled into _NSConcreteGlobalBlock
other times are all _NSConcreteMallocBlock
types, we can see that the initial state of Block's only two, so Block Malloc state is from Stack state change the past, and the author of this conjecture also coincides watching "Objective-C high-level programming" time.
So we're going to explore how it is got from the stack to the heap.
The "Objective-C level programming" Description:
It is obtained by objc_retainBlock()
a method to get the Block stack from the stack,
seen by the runtime / objc-arr.mm objc4 runtime:
objc_retainBlock()
=_Block_copy
When a Block is why as a function of the return value is got heap, it was done?
blk_t func(int rate) {
/*
通过Block语法生成Block,配置在栈上的结构体实例,
tmp被赋值
*/
blk_t tmp = &__func_block_impl_0(...);
/*
通过_Block_copy将其复制到堆上
复制后将堆上的地址作为指针复制给变量tmp
*/
tmp = _Block_copy(tmp);
/*
将堆上的Block作为Objective—C对象
注册到autoreleasepool中,返回该对象
*/
return objc_autoreleaseReturnValue(tmp);
}
Copied in the ARC Block operation is get their own compiler, but the compiler is not a panacea
When used as a return value, the compiler apparently can handle
But then as a function of time is not very good argument to make, and this time we need to manually copy Block, that by "as an argument, automatic variable intercept" Verify that the instance has been verified, it is the type of stack
Here is sure to be asked, why do we have to copy the heap? ? It is not on the stack?
Liang Zi: Security!
Copied onto the heap of __block Block variables and variables are not affected at the end of variable scope
When do you need to manually Copy
Heavy or method parameters passed to Block Function
However, if the appropriate copy of the passed parameters in a method or function, then it is not necessary to call this method before or function manually copied, such as what method:
When the method name and method 1, Cocoa frame has usingBlock like
2, GCD of API