OC面试题 - block相关汇总

block出现之后除了官方原有,几乎很少人再用delegate模式了,很多api也扩展了block模式,block最常见的面试分为:

1.block的基本使用方式

一般来说block都是在回调里面的

void (^block)(int) = ^(int a)
{
   NSLog(@"%d",a);
};
block(3);

不过实际开发要复杂的多了,block(3);一般是另一个类来调用,而block本身也会作为一个参数来传递,使用方式和swift的闭包基本一毛一样,不过原理来说根本就不是一回事了

2.block的原理,本质上block是个啥

block本质就是个类,说白了就是一个类里面有个函数,只是因为外面进行了封装,搞不清这是个啥,因为会捕获外面的属性/变量等等,所以会导致循环引用

OC面试题 - block相关汇总

大概内存结构就是存储了isa和一个__block_impl类(里面有isa 和实际的block函数和一些系统内部的变量,)和一些捕获的变量,如上图所示,age就是捕获的值FuncPtr就是实际的函数

所以其实 这个block不是block类的包本身而是,而且__block_impl这个类,而block(3)这段函数就是

block->FuncPtr(3);这就是Block基本的运行原理

3.block捕获机制

int b = 10;
void (^block)(int) = ^(int a)
{
   NSLog(@"%d,%d",a,b);
};
block(3);

上面代码里面的b就是捕获变量,一般来说捕获的变量主要分两种auto和static,一般没修饰的就是auto,修饰过的就是static,auto捕获的是这个值,比如,b是10里面就是10,就算里面把它修改成了20,外面的b依然是10,而static捕获的是变量的地址,访问方式访问这个地址里面的值,所以里面修改了外面也会修改

4.__block和__weak

__block和__weak都是处理捕获的变量,区别在于,__block修饰的变量会变成修改里面的值,外部也有变化,__weak则是会形成一个弱引用,这个主要应用于强引用造成的循环引用

总结:使用场景一般都是__block修饰本身就是弱引用,但需要里的操作影响外面, 而__weak相反,修饰的是强引用,避免循环引用

6.循环引用

先说说引发条件,block本身在堆上,一般来说就是用copy修饰了block属性(系统的block一般都是这样),然后这个类是A类,则A类强引用了block,block如果也捕获了A类,就比如说在里面用了self,则是最常见的循环引用了,解决办法

1.__weak修饰,几乎我见到的所有操作,都是这个解决方式,这个修饰会形成一个弱引用

__weak typeof(self) weakThis = self;

比如上述代码,这里面原本是block和self这个类,两个强引用,后面添加了weakThis,就变成了self -> block -- weakThis -> self,这样的一个循环引用,最后释放这个block,weakThis就会跟着释放因为它本身是个弱引用,那么没有强引用引用的self自然也可以释放了

2.__unsafe __unretained 修饰 很少见使用方式和上面一样,本质也是不产生强引用弱化一个第三方,然后破解循环引用

3.__block 不过这个只能用于栈内存的block,就比如创建的全部都在一个函数里面,这种场景有点少见,但需要知道这时候__block也能防止循环引用

上一篇:[数据结构]:栈和队列


下一篇:OC笔记 - 静态变量和全局变量的区别