【Objective-C 篇】 ☞ 8. block
block(代码块)
1.1 什么是block
- block是iOS中一种比较特殊的数据类型。(可以定义变量、做形参或返回值)
- block是苹果官方特别推荐使用的数据类型,应用场景比较广泛
- 动画
- 多线程
- 集合遍历
- 网络请求回调
在多线程和网络也使用得相当频繁,一般都是作为回调使用!
- block的作用
- 和函数一样,用来保存某一段代码,可以在恰当的时间再取出来调用
- block功能类似于函数(方法),比函数更强大。
- block是一种数据类型,可以嵌套定义,随时调用。
Xcode输入 inline 可快速生成(快捷键)
1.2 block的格式
- 比较函数、函数指针、block:
如果block没有参数, 那么^后面的()可以省略
- block案例
1.3 给block类型取别名(类比函数指针)
变量的名称就是类型名称(即别名)
1.4 block的应用场景
当前面代码块一样,后面代码块一样,中间的代码块不一样,中间的代码块就用block。
1.5 block的注意事项
- block中可以定义和外界同名的变量,但是在block中访问的是block中定义的变量(就近原则,和函数一样)
- 在代码块中可以访问外面的变量
(1)在代码块中可以直接访问和修改非栈区的变量(使用的是同一个变量)
(2)栈区的变量可以访问,但默认不能修改(使用的是不同的变量,实际上访问的是自己拷贝的值)
block中的变量和外界的局部变量并不是同一个变量,block会将外界的变量拷贝一份到堆内存中
block中使用的外界变量是copy的,所以在调用之前修改外界变量的值,不会影响到block中copy的值
(3)在代码块中修改局部变量编译不通过。怎么在代码块中修改局部变量呢?在局部变量前面加上关键字:__block
1.6 面试题:block是存储在堆中还是栈中?
- 默认情况下block存储在栈中,如果对block进行一个copy操作,block会转移到堆中
- 如果block在栈中, block中访问了外界的对象, 那么不会对对象进行retain操作
- 如果block在堆中, block中访问了外界的对象, 那么会对外界的对象进行一次retain
1.7 block的内存泄露体现
block在copy时都会对block内部用到的对象进行强引用(ARC)或者retainCount增1(非ARC)。
在ARC与非ARC环境下对block使用不当都会引起循环引用问题。
一般表现为:
某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,简单说就是
1)MRC情况下,用__block可以消除循环引用。
2)ARC情况下,必须用弱引用才可以解决循环引用问题,iOS5之后可以直接使用__weak,之前则只能使用__unsafe_unretained了,__unsafe_unretained缺点是指针释放后自己不会置空。
什么时候栈上的Block会复制到堆呢?
- 调用Block的copy实例方法时
- Block作为函数返回值返回时
- 将Block赋值给附有__strong修饰符、id类型的类或Block类型成员变量时
- 在方法名中含有usingBlock的Cocoa框架方法或GCD的API中传递Block时
block很多的用处是跨越两个类来使用的。
实现两个页面之间的传值:
- 通过“协议/代理”实现两个页面之间传值
- 使用block作为property,实现两个页面之间传值
面试题: