乐趣区

关于objective-c:iOS开发面试只需知道这些技术基本通关block篇

一、什么是 Block?

Block 是将函数及其执行上下文封装起来的对象。
比方:

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

其中 WYTest 是文件名,blockTest 是办法名,这些能够疏忽。其中 WYTest blockTest_block_impl_0  构造体为

--block_impl 构造体为

block外部有 isa 指针,所以说其本质也是 OC 对象

block 外部则为:

所以说 Block 是将函数及其执行上下文封装起来的对象

既然 block 外部封装了函数,那么它同样也有参数和返回值。

二、Block 变量截获

1、局部变量截获 是值截获。比方:

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

打印为 1,2,3

部分对象变量也是一样,截获的是值,而不是指针,在内部将其置为 nil,对 block  没有影响,而该对象调用办法会影响

2、部分动态变量截获 是指针截获。

输入为 2,意味着 num = 1 这里的批改 num 值是无效的,即是指针截获。同样,在 block 里去批改变量 m,也是无效的。

首先作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是本鑫一个 iOS 开发公众号:编程大鑫,不论你是小白还是大牛都欢送入驻,让咱们一起提高,独特倒退!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)

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持有 blockblock  持有 --block  变量,而 --block 变量持有 self,造成内存透露。

比方:

如果要解决这种循环援用,能够被动断开 --block 变量对 self 的持有,即在 block外部应用完 weakself 后,将其置为 nil,但这种形式有个问题,如果 block 始终不被调用,那么循环援用将始终存在。

所以,咱们最好还是用 --weak 来润饰 self

以上就是 block 篇的面试题合集了,感激观看~!

退出移动版