一、什么是Block?
Block 是将函数及其执行上下文封装起来的对象。 比如:

通过 clang -rewrite-objc WYTest.m
命令编译该.m
文件,发现该 block
被编译成这个形式:

其中 WYTest
是文件名,blockTest
是方法名,这些可以忽略。其中WYTest blockTest_block_impl_0
结构体为

--block_impl
结构体为

block
内部有 isa
指针,所以说其本质也是 OC
对象
block
内部则为:

所以说 Block
是将函数及其执行上下文封装起来的对象
既然 block
内部封装了函数,那么它同样也有参数和返回值。
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群1012951431来获取一份详细的大厂面试资料为你的跳槽多添一份保障。
二、Block变量截获
1、局部变量截获 是值截获。 比如:

这里的输出是 6 而不是 2,原因就是对局部变量 num
的截获是值截获。同样,在 block
里如果修改变量 num
,也是无效的,甚至编译器会报错。

打印为 1,2,3
局部对象变量也是一样,截获的是值,而不是指针,在外部将其置为 nil
,对 block
没有影响,而该对象调用方法会影响
2、局部静态变量截获 是指针截获。

输出为 2,意味着 num
= 1 这里的修改num
值是有效的,即是指针截获。同样,在 block
里去修改变量 m
,也是有效的。
3、全局变量,静态全局变量截获:不截获,直接取值。 我们同样用 clang
编译看下结果。

编译后

( impl.isa
= &_NSConcreteStackBlock
;这里注意到这一句,即说明该 block
是栈 block
)
可以看到局部变量被编译成值形式,而静态变量被编成指针形式,全局变量并未截获。而--block
修饰的变量也是以指针形式截获的,并且生成了一个新的结构体对象:

该对象有个属性:num5
,即我们用--block
修饰的变量。这里--forwarding
是指向自身的(栈 block
)。
一般情况下,如果我们要对 block
截获的局部变量进行赋值操作需添加--block
修饰符,而对全局变量,静态变量是不需要添加--block
修饰符的。
另外,block
里访问 self
或成员变量都会去截获self
。
三、Block的几种形式
分为全局 Block(_NSConcreteGlobalBlock)
、栈 Block(_NSConcreteStackBlock)
、堆
Block(_NSConcreteMallocBlock)
三种形式
其中栈 Block
存储在栈(stack)
区,堆 Block
存储在堆(heap)
区,全局 Block
存储在已初始化数据(.data)
区
1、不使用外部变量的block是全局block 比如:

输出:

2、使用外部变量并且未进行copy操作的block是栈block
比如:

输出:

日常开发常用于这种情况:

3、对栈block进行copy操作,就是堆block,而对全局block 进行copy,仍是全局block
比如堆 1中的全局进行 copy
操作,即赋值:

输出:

仍是全局 block
而对 2中的栈 block
进行赋值操作:

输出:

对栈 blockcopy
之后,并不代表着栈 block
就消失了,左边的 mallock
是堆 block
,右边被 copy
的仍是栈block
比如:

输出:

即如果对栈Block
进行cop
,将会copy
到堆区,对堆Block
进行copy
,将会增加引用计数,对全局 Block
进行copy
,因为是已经初始化的,所以什么也不做。
另外,--block
变量在 copy
时,由于--forwarding
的存在,栈上的--forwarding
指针会指向堆上的--forwarding
变量,而堆上的--forwarding
指针指向其自身,所以,如果对--block
的修改,实际上是在修改堆上的--block
变量。
即 --forwarding
指针存在的意义就是,无论在任何内存位置,都可以顺利地访问同一个 --block
变量。
另外由于 block
捕获的--block
修饰的变量会去持有变量,那么如果用 --block
修饰 self
,且 self
持有
block
,并且 block
内部使用到--block
修饰的 self
时,就会造成多循环引用,即 self
持有 block
,block
持有--block
变量,而--block
变量持有 self
,造成内存泄漏。
比如:

如果要解决这种循环引用,可以主动断开--block
变量对 self
的持有,即在 block
内部使用完 weakself
后, 将其置为 nil
,但这种方式有个问题,如果 block
一直不被调用,那么循环引用将一直存在。
所以,我们最好还是用--weak
来修饰 self
以上就是block
篇的面试题合集了,感谢观看~!
文末推荐:iOS热门文集
- 面试基础
iOS面试基础知识 (一)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (二)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (三)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (四)
https://github.com/iOS-Mayday/heji
iOS面试基础知识 (五)
https://github.com/iOS-Mayday/heji
- 知识详解
iOS面试要点之GCD面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之多线程面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之block面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之Runtime面试要 点
https://github.com/iOS-Mayday/heji
iOS面试要点之RunLoop面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之内存管理面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之MVC、MVVM面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之网络性能优化要点
https://github.com/iOS-Mayday/heji
iOS面试要点之网络编程面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之KVC&KVO面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之数据存储面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之混编技术面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之设计模式面试要点
https://github.com/iOS-Mayday/heji
iOS面试要点之UI面试要点
https://github.com/iOS-Mayday/heji
网友评论