myBlk clang后转换为 Blcok的结构体类型的自动变量
__block 变量a clang 后转换成 __block变量的结构体类型的自动变量
他们都在存储在栈区上
_NSConcreteStackBlock 栈
_NSConcreteGlobalBlock 全局区(静态区) 准确说是 .data区 .data区是放已被初始化的全局、静态)
_NSConcreteMallocBlock 堆
什么样的Block 设置在全局区、什么样的在栈区??
没有引用自动变量的block叫做NSGlobalBlock, (引用全局或者外部变量还是NSGlobalBlock)
其余Block生成的Blcok 为 NSStackBlock类对象, 且设置在栈区
配置在堆区上的Block 类 何时使用?
这正是上一篇博客留下的问题:Blcok 超出变量作用域可存在的原因?
配置在栈区的Block, 其作用域结束时,该Block就被废弃了。 __block 也是配置在栈区,作用域结束时同样也会被废弃。
全局区的block 作用域广,所以不会有这种问题,但是全局Block 是不捕获自动变量的。用的也少。
那怎么解决栈区Block 过了作用域销毁的问题呢?
Blocks 提供了将Block 和 __block变量 从栈上 复制到 堆上 的方法 来解决这个问题。将栈上的Blcok 复制到堆上,这样即使Block的变量作用域结束了,堆上的Block还可以继续存在。
这就解决了过了作用域销毁的问题
在看__forwarding 的问题, __block变量用结构体成员变量__forwarding可以实现无论__block变量配置在栈上还是堆上,都能正确的访问__block结构体变量。
栈区block copy 后从栈区到堆区
全局block copy 后什么也不做
堆区block copy 后引用计数增加
所以 不管Block配置在何处,用copy都不会引起任何问题。但是copy是相当消耗CPU资源的,当Block在栈区可以使用时,就不要copy进堆区。
且在 ARC中多次copy 也没有任何问题。 ARC中大部分情况系统都帮你做了copy,只有 向方法或函数的参数传递Block时,系统不会自动copy。 但是如果在方法或函数中适当地复制了传递过来的参数,就不用在调用方法或函数前手动复制了。比如有些方法就为我们这么设计了:
1.cocoa框架的方法且方法名中含有usingBlock的方法
2.GCD 的API
具体举例:NSArray类的 enumerateObjectsUsingBlock 实例方法
GCD的 dispatch_async函数
都不需要手动复制。
需要手动复制的方法:
NSArray initWithObjects 实例方法上传递Block是需要手动复制
原因是:block是栈区block 过了作用域,block就销毁了。
解决办法:将block 复制到堆区。