block的实质:
block实质是oc对闭包的对象实现,简单点来说 block就算是对象。
block的书写方式:
//block 的一般形式
int(^myBlock)(int) = ^(int count) {
return count + 1;
};
//可以使用typedef定义相同类型的block
typedef int (^commentBlock)(int);
commentBlock blc = ^(int abc) {
return abc;
};
Block可以截获局部变量。
修改Block外部的局部变量,Block内部被截获的局部变量不受影响。
修改Block内部到局部变量,编译不通过。
typedef void (^myBlock)(void);
int a = 10;
int b = 20;
myBlock blk = ^(void) {
NSLog(@"a = %d b = %d", a, b);
};
blk();
a+= 10;
b+= 10;
blk();
通过打印得知两次打印结果一样,block内部可以截获局部变量,是另外一份,不再受原来的变量影响。
局部变量在block内部不是指针传递,而是值传递。所以外部的值改变不会影响内部的值。
想要可以修改局部变量,有两种方法
1.改变存储于特殊存储区域的变量。
全局变量、静态变量和静态全局变量都可以在block内部直接修改。
2.通过__block修饰符来改变。
__block说明符用于指定将变量值设置到哪个存储区域中,也就是说,当自动变量加上__block说明符之后,会改变这个自动变量的存储区域。
三种block
1.全局block、
在全局区域生成的全局block。
存储在程序的数据区域。
copy之后无变化。
2.栈block
正常的方法中生成的block。
存储在栈上,copy之后存储在堆上。
3.堆block
栈block copy到堆之后就生成了堆block。
存储在堆上,copy之后引用计数增加。
大部分block创建之后会自动copy到堆上。
在block被copy到堆上的时候,block通过__block持有的变量也一块被copy进去。等到block被废弃,没有block持有该变量的时候,变量自动释放。
block循环引用
如果在Block内部使用__strong修饰符的对象类型的自动变量,那么当Block从栈复制到堆的时候,该对象就会被Block所持有。
所以如果这个对象还同时持有Block的话,就容易发生循环引用。
最常见的情况就是控制器self创建了一个block变量,控制器self持有该block。同时如果该block内部引用self,此时就形成了相互持有死循环。