Block有三种类型:__NSGlobalBlock,__NSStackBlock,__NSMallocBlock
问题:
Block有几种类型呢?这几种类型分别在什么情况下出现?
我们思考一下,__NSStackBlock
在访问外部变量时,会有什么问题?
我们在讲block的本质的时候已经知道了,block的本质就是一个 OC 对象,那么既然它是一个 OC 对象,它就会有类型,本文就将讲解block
的三种类型.并都继承于NSBlock
我们在讲block
的三种类型之前,先了解一下程序的内存分配情况,因为不同类型的block
分配的内存也不同.
- .text段 : 也称代码段,我们写的代码都存放在这里
- .data区 : 也称数据区,一般存放全局变量, __NSGlobalBlock存放在这里
- 堆区 : 存放我们自己
alloc
出来的对象,动态分配内存,需要程序员自己申请内存,自己管理. __NSMallocBlock存放在堆区 - 栈区 : 一般存放局部变量,不需要程序员管理,系统自动分配,自动销毁,__NSStackBlock存放在栈区
不同block类型的内存分配
一: __NSGlobalBlock
结论: 没有访问 auto变量 的block 就是 __NSGlobalBlock
int main(int argc, const char * argv[]) { @autoreleasepool { static int age = 10; void(^block)(void) = ^{ NSLog(@"Hello, World! %d",age); }; NSLog(@"%@",[block class]); } return 0; } 控制台输出:__NSGlobalBlock__
这个很好理解,不过多解释
二: __NSStackBlock
结论:访问了auto变量 的block 就是 __NSStackBlock
int main(int argc, const char * argv[]) { @autoreleasepool { int age = 10; void(^block)(void) = ^{ NSLog(@"Hello, World! %d",age); }; NSLog(@"%@",[block class]); } return 0; } 控制台输出:__NSMallocBlock__
怎么打印的是__NSMallocBlock__
,刚才不是说访问了auto变量
就是__NSStackBlock
吗?
因为这里我们使用的是ARC,在ARC环境下,Xcode编译器再某些情况会默认帮我们做调用copy 变成堆block ,我们在Build Settings中把ARC设置成MRC,再来打印一下:
2018-08-30 17:37:09.846365+0800 block的类型[4318:3463149] __NSStackBlock__
这次打印的就是__NSStackBlock__
我们思考一下,__NSStackBlock
在访问外部变量时,会有什么问题?
会出现野指针crash 所以在ARC坏境Xcode帮我们处理成了堆block(__NSMallocBlock__)防止出现释放了还去访问导致野指针crash
所以,为了避免出现这种情况,我们需要把block
存储在堆上,__NSMallocBlock
就闪亮登场了.
三: __NSMallocBlock
结论: 当一个__NSStackBlock
调用了copy
操作,返回的就是一个__NSMallocBlock
思考:如果我们对__NSStackBlock
进行一次 copy
操作,会发生什么变化呢?
__NSStackBlock copy后
‼️注意
以上都是在MRC环境下
如果是在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上, 比如以下几种情况:
-
1. block作为函数返回值时
block作为返回值编译器会自动copy
-
2.将block赋值给__strong指针时
被强指针引用的block会自动copy
-
3.block作为Cocoa API方法名含有UsingBlock的方法参数时
UsingBlock
- 4.block作为GCD API的方法参数时
- 5.block调用copy方法
总结:
- 1:一共有三种类型的Block.分为
__NSGlobalBlock
,__NSStackBlock
,__NSMallocBlock
.
- 没有访问 auto变量 的
block
就是__NSGlobalBlock
- 访问了auto变量 的
block
就是__NSStackBlock
- 当一个
__NSStackBlock
调用了copy操作,返回的就是一个__NSMallocBlock
sing
- 没有访问 auto变量 的
- 2:在ARC环境下,编译器会自动把栈上的
block copy
到堆上