Q: 什么是Block?
A: Block是将函数及其执行上下文封装起来的对象。
Q: 怎样理解Block调用?
A: Block调用就是函数的调用
Q: Block的一大特性是截获变量,那么系统关于Block截获变量是怎样实现的?
Q: 会使用__block修饰符,这修饰符用于做什么?
Q: 什么时候需要对Block进行copy操作?
Q: 栈Block,堆Block是否了解?
isa指针,是Block是对象的标志
FuncPtr是函数指针,会指向具体的函数实现。
通过函数指针,得到相应的函数执行体。
截获变量
Q:对Block截获变量的特性是否有了解?
A:
1).对于基本数据类型的局部变量截获其值 (值类型)
2).对于对象类型的局部变量连同所有权修饰符一起截获(例如__unsafe_unretained id unsafe_obj = nil;
__strong id strong_obj = nil; 循环引用跟所有权修饰符一起截获是有关的)
3).以指针形式截获局部静态变量(引用类型)
4).不截获全局变量,静态全局变量
__block修饰符
-
一般情况下,对被截获变量进行赋值操作,需要加__block修饰符
1.使用,不需要__block
2.赋值,需要__block
3.对变量赋值,需要__block
4.对变量赋值,不需要__block
__block修饰的变量变成了对象
栈上的__forwarding指针指向自己。
__forwarding指针是用来做什么的?
Block内存管理
Q:何时需要对block进行copy操作?
对于不同类型的block, copy的结果也不一样。
Q:当对栈上block进行copy操作后,在MRC环境下,是否会引起内存泄漏呢?
A:会。copy操作后, 堆上的block没有其他额外的成员变量指向它,跟alloc出一个对象,没有给出相应的release操作一样,产生内存泄漏。
栈上__block变量的copy
Q:栈上的__forwarding指针的用处?
A: 栈上的__forwarding指针指向的是堆上的block变量,堆上的__forwarding指针指向的是自身。
如果要修改栈上block,如果做过copy操作,实际上修改的就不是栈上的__forwarding对应的值,而是通过通过栈上block的__forwarding指针找到堆上的__forwarding变量,然后对堆上的multiplier值进行修改,比如改成4。
同样的,如果是__block变量,由于被成员变量持有,当我们在其他地方调用__block变量的修改,实际是通过自身的__forwarding指向来修改的。
__forwarding存在的意义
Block循环引用
由于block对其截获的变量,是连其所有权修饰符一并截获。
因此,block内部的持有的变量,也是__weak类型。
Q:以下代码有什么问题?
A:在MRC下,不会产生循环引用,在ARC下,会产生循环引用,引起内存泄漏。
这个解决方案的原理是,在block内部把blockSelf置为nil,从而断开了对对象的持有。但是有一点很重要,如果一直不调用block, 就没机会断开对象的持有,也就无法解决循环引用了
总结
Q:为什么block会产生循环引用?
A:当前block对当前某一对象进行截获,block会对对应变量强引用,当前block又由于当前对象对其有一个强引用,因此就产生了一种自循环引用的循环引用问题,可以声明为__weak变量来进行循环引用消除。如果定义了__block修饰符,一种是在MRC下,MRC不会产生循环引用,一种是在ARC下,可以通过断环的方式解除对应循环引用。有一个弊端,如果block一直不能被调用,循环引用是不能被解除的。
Q:你都遇到过哪些循环引用,是怎么解决的?
A:
1). NSTimer
2). block循环引用, __weak解除