《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》(第三十七条:理解“块”这一概念)笔记
要点如下:
1、块用 ^ 表示,语法结构:
返回值类型 (^block名) (参数类似 参数名),如:
id (^responseBlock)(id obj)
2、块其实就是个值,可以把块赋值给变量,然后像其他变量一样使用
3、块的强大之处在于:
在定义块的范围里(简单理解就是块所在的方法里)的所有变量,在块里都可以使用
4、默认情况下,块捕获的变量不可修改;__block修饰的变量才可以在块中修改
5、块会将捕获到的变量都浅拷贝一份(即会保留捕获的变量,使其引用计数加1)
非OC类型的变量拷贝的是值,加__block之后才是进行浅拷贝
6、块也有引用计数,引用计数为0块被释放,同时释放所捕获的变量
7、实例方法中的块,可以访问类的所以实例变量,以及self变量
块总能修改实例变量,且不用加__block
块里使用实例变量时,self也会被捕获,因为实例变量是与self关联的。
块捕获self后会保留它,这时如果self中也有这个快,就会导致”保留环“
8、块的结构体:
typedef struct block{
Class isa; //isa指针,说明块也是OC对象
int flags;
int reserved;
void (*)(void * ...) invoke; //invoke变量是函数指针,指向块的实现代码,参数(void * ...)代表块
struct *descriptor; //其中包含了块的大小,及复制块、释放块等函数指针
捕获的变量; //块会将捕获到的变量都浅拷贝一份(即会保留捕获的变量,使其引用计数加1)
}
注:isa指针可以参数:类对象
9、块需要用copy拷贝
因为块定义的时候是分配在栈中,只在定义它的范围内有效(”栈块“)
用copy拷贝后,就复制到了堆中,也就成了带引用计数的OC对象了(”堆块“)
多次copy块只是引用计数增加
10、全局块:
不会捕获外围变量
在全局内存中,内存区域在编译期就已确定
是单例,copy是空操作
块内不需要外部变量时,可将块写为全局块
11、typedef定义块类型:
typedef 返回值类型 (^block名) (参数)
用定义的块类型创建块变量
block名 变量A
变量A即可像其他变量一样使用