小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
什么是Block Block是将函数及其执行上下文封装起来的对象。 什么是Block调用 Block调用即是函数的调用。 Block的几种形式(类型) Block有三种形式,包括:
- 全局Block(
_NSConcreteGlobalBlock
):当我们声明一个block时,如果这个block没有捕获外部的变量,那么这个block就位于全局区(已经初始化数据(.data
)区)。 - 栈Block(
_NSConcreteStackBlock
):- 1.ARC环境下,当我们声明并且定义了一个block,系统默认使用
__strong
修饰符,如果该Block捕获了外部变量,实质上是从__NSStackBlock__
转变到__NSMallocBlock__
的过程,只不过是系统帮我们完成了copy操作,将栈区的block迁移到堆区,延长了Block的生命周期。对于栈block而言,变量作用域结束,空间被回收。 - 2。ARC环境下,如果我们在声明一个block的时候,使用了
__weak
或者__unsafe_unretained
的修饰符,那么系统就不会做copy的操作,也就不会将其迁移到堆区。
- 1.ARC环境下,当我们声明并且定义了一个block,系统默认使用
- 堆Block(
_NSConcreteMallocBlock
):- 1.在MRC环境下,我们需要手动调用copy方法可以将block迁移到堆区
- 2.而在ARC环境下,
__strong
修饰的(默认)block捕获了外部变量就会位于堆区,NSMallocBlock
支持retain
、release
,会对区引用计数+1或-1. - 只有局部变量和定义的属性才会拷贝到堆区。
- 存储在程序的数据区域,在block内部没有引用任何外部变量。
- 使用外部变量并且未进行copy操作的block是栈block。
- 对栈block进行copy操作,就是堆block,对堆block进行copy,将会增加引用计数。对全局block进行copy,仍是全局block。 在什么场景下使用__block修饰符呢?
- 1.对截获变量进行赋值造作需要添加
__block
修饰符(赋值 != 使用)。 - 2.对局部变量(基本数据类型和对象类型进行赋值需要
__block
修饰符。其内部其实是对该__bloc
k对象进行拷贝,所以通过__block
可以修改被截获变量的值且不会和外部变量互相影响。 - 3.对静态局部变量、全局变量、静态变量不需要
__block
修饰符。 block的截获变量特性? 基本数据类型的局部变量 Block 可以截获其值。 对于对象类型的局部变量联通所有权修饰符一起截获。 局部静态变量以指针的形式进行截获。 全局变量和静态全局变量,block是不截获的。 weak打破Block循环引用原理
block内部操作的weakSelf的指针地址,它和self是两个不同的指针地址,即没有直接持有self,所以可以weakSelf可以打破self的循环引用关系self - block - weakSelf。