问题:根据Block在内存中的位置谈谈Block
2020-05-08 本文已影响0人
姜小舟
根据Block在内存中的位置分为三种:
- 全局Block(_NSConcreteGlobalBlock)----存储在已初始化数据(.data)区
- 栈Block(_NSConcreteStackBlock)-----存储在栈(stack)区
- 堆Block(_NSConcreteMallocBlock)-----存储在堆(heap)区
1.不使用外部变量的block是全局block
NSLog(@"%@",[^{
NSLog(@"globalBlock");
} class]);
#输出:
#__NSGlobalBlock__
2.使用外部变量并且未进行copy操作的block是栈block
NSInteger num = 10;
NSLog(@"%@",[^{
NSLog(@"stackBlock:%zd",num);
} class]);
#输出:
#__NSStackBlock__
日常开发常用于这种情况:
[self testWithBlock:^{
NSLog(@"%@",self);
}];
- (void)testWithBlock:(dispatch_block_t)block {
block();
NSLog(@"%@",[block class]);
}
3.对栈block进行copy操作,就是堆block。而对全局block进行copy,仍是全局block
比如对1.中的全局Block进行copy操作,即赋值:
void (^globalBlock)(void) = ^{
NSLog(@"globalBlock");
};
NSLog(@"%@",[globalBlock class]);
#输出仍是全局block:
#__NSGlobalBlock__
而对2.中的栈Block进行赋值操作:
NSInteger num = 10;
void (^mallocBlock)(void) = ^{
NSLog(@"stackBlock:%zd",num);
};
NSLog(@"%@",[mallocBlock class]);
#输出是堆block:
#__NSMallocBlock__
对栈Block进行copy之后,并不代表着栈Block就消失了,左边的mallock是堆Block,右边被copy的仍是栈Block
比如:
[self testWithBlock:^{
NSLog(@"%@",self);
}];
- (void)testWithBlock:(dispatch_block_t)block {
block();
dispatch_block_t tempBlock = block;
NSLog(@"%@,%@",[block class],[tempBlock class]);
}
#输出:
#__NSStackBlock__,__NSMallocBlock__
综上所述:
- 对栈Block进行copy,将会copy到堆区
- 对堆Block进行copy,将会增加引用计数
- 对全局Block进行copy,因为是已经初始化的,所以什么也不做。
另外,__block变量在copy时,由于__forwarding的存在,栈上的__forwarding指针会指向堆上的__forwarding变量,而堆上的__forwarding指针指向其自身,所以,对__block变量的修改,实际上是在修改堆上的__block变量。即:__forwarding指针存在的意义就是,无论在任何内存位置,都可以顺利地访问同一个__block变量。