1:block捕获局部变量的能力:无论是基础数据类型还是对象,被捕获的都是局部变量里所存储的瞬时值,所以局部变量本身里面的存储值没法被更改。只不过,如果局部变量里存的是个对象的内存地址,那block截获的实际是那个对象的地址,当然能更改对象的属性。
block只有用了那个局部变量,才会捕获谁,所以block是有size的。
注意block捕获变量的时机,在block被创建时变量即被捕获。并不是等到执行此block代码块时才捕获变量。
2:那如果局部变量加了__block呢,那就不会捕获瞬时值了,相当于正常访问,捕获(或叫复制)的是其本身的内存地址。将其封装成了一个放在堆上的结构体,以方便从栈上和堆上访问和修改同一份数据,即使局部变量被释放了,在block内依然能继续访问。 所以可以正常修改等操作。加了static关键字,也能达到相似的效果。
3:循环引用问题
达到循环引用的条件:block中持有的对象,直接或间接的持有本block。
但作为函数参数的block中,访问self会不会造成循环引用呢,答案是不会的。因为作为方法参数的block体并没有被任何方持有,是栈block,出了作用域即释放。
所以,在gcd、Masonery或者网络请求封装成的回调block中,直接访问self并不会造成循环引用。但是有一点要注意,在block中再有block使用直接或间接使用self时,最好使用__strong保持self,不然使用时可能已经被释放成nil 。
4:block类型
block分为栈 、 堆 、全局block。
堆block不能被直接创建,只能被copy到堆上。
因为block变量默认是声明在栈变量上的,为了能在block的声明域外使用,所以要把block copy到堆上。所以说,为了block属性声明和实际的操作一致,做好声明为copy。
全局block:定义全局区变量的地方有block语法时;block语法的表达式中没有使用到应截获的自动变量时。
栈block:在某个方法中,捕获并使用了局部变量;
堆block:调用Block的copy实例方法时;
Block作为函数返回值返回时;
将Block赋值给附有__strong修饰符id类型的类或Block类型成员变量时;
将方法名中含有usingBlock的Cocoa框架方法或GCD的API中传递Block时;
5:block的作用
本质是匿名函数,再本质就是结构体。
可作为属性、参数或返回值。
作为参数、属性、或返回值时,block可传入参数,实现block体,达到回调的效果。
网友评论