定义
带有局部变量(自动变量)的匿名函数
ps :
“带有局部变量”:可以获取到块外面的变量(将变量放在自身(block)的结构体中;获取的只是改变量的瞬时值,后面对变量的修改不会使块中的变量也被修改),但是只能读取;
要改写的话需给变量前面加"__block"修饰符 _(将该变量变成和Block一样的结构体实例,并在自身的结构体添加一个对结构体中值的指针引用;分开两个结构体(block的结构体 , 变量的结构体)是为了能够在多个Block中用到_block变量)
本质
C语言中的结构体和函数,OC语言中对象
语法
^ 返回值类型 参数列表 表达式(斜体代表可省略)
ps:
省略返回值类型时,如果表达式中有return就使用该返回值的类型,如果没有return就使用void类型;表达式中含多个return语句时,所有return的返回值类型必须一致
分类
所属类 | 说明 | |
---|---|---|
栈块 | _NSConcreteStackBlock | 编译器会给每个块分配好栈内存, 然而等离开了相应的范围之后,编译器有可能把分配给块的内存覆写掉。 |
堆块 | _NSConcreteMallocBlock | 带引用计数的块对象;栈块通过copy方法可成为堆块 |
全局块 | _NSConcreteGlobalBlock (存储域为程序的数据区域 .data区) | 块不会捕捉任何状态(比如外围的变量等),运行时也无须有状态来参与。块所使用的整个内存区域,在编译期已经完全确定了。 |
ps:全局块:对其的拷贝操作是个空操作,因为全局块决不可能为系统所目收。这种块实际上相当于单例。下面就是个全局块:
void (^ablock)() = ^{
NSLog(@"This is a block");
}
由于运行该块所需的全部信息都能在编译期确定,所以可把它做成全局块。这完全是种优化技术:若把如此简单的块当成复杂的块来处理,那就会在复制及丢弃该块时执行
)
从栈到堆
对于Block (用copy方法)
使用场景:向方法或函数的参数中传递Block时
不需手动复制的情况:
Cocoa框架的方法且方法名中含有usingBlock时
GCD的API
将block作为函数返回值返回时,将Block赋值给用__strong修饰的id类或Block类型成员变量时,编译器会自动将对象的Block作为参数并调用_Block_copy函数(和copy效果一样)
源存储域 | 复制效果 |
---|---|
栈 | 栈 -> 堆 |
堆 | 引用计数增加 |
程序的数据区域 | 什么也不做 |
对于__block变量
跟随Block移动:当一个引用__block变量的Block从栈到堆时,__block变量也从栈到堆,并持有该变量;当有另外一个也引用了该__block变量的Block从栈到堆时,该Block也持有该变量并且该变量引用计数加一,
参考资料:
《Objective-C高级编程》