一、什么是 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
持有 block
,block
持有 --block
变量,而 --block
变量持有 self
,造成内存透露。
比方:
如果要解决这种循环援用,能够被动断开 --block
变量对 self
的持有,即在 block
外部应用完 weakself
后,将其置为 nil
,但这种形式有个问题,如果 block
始终不被调用,那么循环援用将始终存在。
所以,咱们最好还是用 --weak
来润饰 self
以上就是 block
篇的面试题合集了,感激观看~!