block代码块(数据库中最小存储和处理单位)本质上是和其他变量类似。不同的是代码块存储的数据是一个函数体。使用代码块你可以像调用其他标准函数一样,传入参数,并得到返回值。
大神理解说block就是objc的闭包功能,于是我就去看了下闭包是什么东西?
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
举例说明:
先看看数学上的闭包。(1,5) 是一个区间,但对这个区间做分析、计算什么的,经常会用到1和5这两个不属于这个区间的值,[1,5]就是(1,5)的闭包。
(看完上面的是不是觉得懵逼了,看看总结你的心情能好点)
总结:
(1)闭包是一种设计原则,它通过分析上下文,来简化用户的调用,让用户在不知晓的情况下,达到他的目的;
(2)网上主流的对闭包剖析的文章实际上是和闭包原则反向而驰的,如果需要知道闭包细节才能用好的话,这个闭包是设计失败的;
(3)尽量少学习。
回到block(开始真正深入了解)
一、block的存储区域
验证方法可以把block当做对象打印,不一样的定义法会打印出不同的类型分别有三种_NSConcretStackBlock、 _NSConcretGlobalBlock、 _NSConcretMallocBlock,这说明了block的三种存储方式:栈、全局、堆
二、如何定义block
1.
当然这只是为了说明block才这么写,使用中我们不会这么写的,block在使用过程中相当于保存了一段代码,想要使用的时候调用
2.开发中使用block
typedef void(^HeBlock)();
@property (nonatomic, copy) HeBlock block;
这里定义block,往block中写入自己想要实现的代码
我这里是在点击屏幕的时候调用block
注意点:
1.如果block中没有使用外部变量,默认就是存在全局区的
2.如果block中使用了外部变量,就是在堆中(原因:默认在ARC中局部变量是强指针,这样保证局部变量所在的代码模块运行完成才销毁局部变量,所以强指针就把block放堆里了(这句所以我有点懵逼))
block引用基本数据类型
1.局部变量
局部自动变量,在Block中只读。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响他在Block中的值
对于用__block修饰的外部变量引用,block是复制其引用地址来实现访问的,所以是可修改的
2.Static修饰符的全局变量
因为全局变量或静态变量在内存中的地址是固定的,Block在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量.
ARC对block类型的影响
在ARC开启的情况下,将只会有NSConcretGlobalBlock和NSConcretMallocBlock类型的block
使用block过程中循环引用的问题
循环引用指两个对象相互强引用了对方,即retain了对方,从而导致谁也释放不了谁的内存泄露问题。如声明一个delegate时一般用assign而不能用retain或strong,因为你一旦那么做了,很大可能引起循环引用。在以往的项目中,我几次用动态内存检查发现了循环引用导致的内存泄露。
这里讲的是block的循环引用问题,因为block在拷贝到堆上的时候,会retain其引用的外部变量,那么如果block中如果引用了他的宿主对象(大多数情况是self 拥有一个block的时候,在block 又调用self的方法。形成你中有我,我中有你,谁都无法将谁释放的困局。),那很有可能引起循环引用
推荐使用前两种方法:
1. 使用__weak修饰符。__weak id weakObj = obj
2.使用__unsafe_unretained修饰符。__unsafe_unretained id unretainObjc= obj
3. 使用__block修饰符。__block id tmp = self;然后在block中tmp = nil;这样就打破循环了。这个办法需要记得将tmp=nil