iOS block详解
主要是用在响应事件和传值上,比如我们经常用的AFN就会用block进行回调传值.
一.什么是block?
block本质是一个对象,也是一个匿名函数(用函数式编程进行了保存,底层是有名的). 在底层的__main__block__impl__0 上有指出block是isa指针对象
总结:block是一个带有自动变量的匿名函数
二.为什么block可以捕获外部变量
是因为__main__block__impl__0会自动生成相应属性
三.为什么内部属性没法修改(没有用__block修饰)
因为内部的属性是拷贝过去的,是浅拷贝,只拷贝了对象值,未拷贝指针,因此你内部修改没法改变外部变量,或者也可以理解为内部的变量只是在变量空间中的临时变量作出了改变,并没有影响外部,所以会造成代码歧义.比如内部是18 外面是19.
用__block修饰的变量,在拷贝的时候会把指针一个拷贝进去
四.block有几种类型
block有三种,全局静态block 栈区block和堆区block
NSGolobalBlock 全局静态 不使用外部变量的block,或者只使用静态变量和全局变量
NSMallocblock 堆区block 使用外部变量且赋值的强引用 ----出了作用域会释放{ } 才会持有对象
NSStackBlock 栈区block 使用外部变量但未进行COPY,或者引用的weak变量 ----系统决定释放
__weak 和__strong 修饰的block,内部捕获的变量就是什么类型,前者也是weak,后者retain+1
在内部用__strong,其实是把__weakself从弱引用列表给拉出了,会持有self,所以就算VC已经销毁,但是block里面还是在持有它,看持有的时间,如果是设置的延迟5秒,那就会延迟5秒再销毁.
为什么内部用__strong修饰不会造成强引用呢,因为外部是用__weak修饰的,所以内部就算是__strong修饰,那也是一个
五.循环引用解决问题
[UIView animation]方法为啥不会有循环引用,因为持有block 的是UIView ,并不是self
解决循环引用问题
方法1. weak--strong -- dance 强弱共舞
__weak typeof(self) weakself= self;
self.block = ^{
__strong typeof(weakself) strongself = weakself;
方法
}
方法2.利用__block手动释放
__block 当前VC * vc = self ;
self.block = ^{
方法
self = nil ;
}
方法3.我们使用self的目的还是使用当前VC的参数
可以当前VC在定义block的时候作为一个参数,然后在内部调用参数对象来获取需要的属性和值
typeofdef void (^block)(vc*); 定义block的时候把要引用的self设置为参数
六 .为什么会造成循环引用?
例子:定义一个block,和name属性,block内部打印@"self.name"属性,然后block()调用一下.
如果单纯用weak解决循环引用的问题是没有问题的,可以释放,但是有可能造成提前释放,比如我在block里面进行一个耗时操作,自定义一个dispatch_after 2秒 ,我self释放以后,block内部调用的方法还没做呢,数据就已经释放了,就没法完成我们的需求,所以用__strong修饰一下
__strong typedef(weakself) strongself = weakself; 这个记得不要放在延时操作里面,不然一样的会提前释放
七 .block的基本使用
1.作为属性:常用在按钮的点击事件回调和值的逆传
界面2跳回界面1,我们要回传值的话,必须声明带参数的block属性(注意区别,这里不是声明一个方法带block作为参数,而是声明一个block属性,block本身带参数,也就是第二个括号里带上东西。这个参数就是你要回调的值),当你在界面2里调用这个方法的时候把值传进去,你在界面1获取到界面2block属性的时候就能取到你传过去的值。怎么在界面2把值弄进去?同按钮点击事件回调一样,只不过方法实现括号里有东西,所以其实按钮点击事件回调也可以传值,两个可以一起做,这个我觉得放在一起来比较好理解。也就是说作为属性的时候既可以传递事件,也可以传递值
在控件的跳转界面那里进行点语法,然后点出block,在里面进行事件操作,记得在按钮界面.m文件里判断是否执行,如果执行了才调用
2.作为参数的时候 :常用做传值
作为参数的也可以传值,那可能有同学就会问,和作为属性有啥区别?
比如,AFN网络请求数据,我们写的网络请求方法里面会带block参数,并在方法的实现里面把获取到的值传进block通过赋值,然后我们在调用网络的时候的时候进行值传递获取到值。
作为属性的时候一般是响应事件的传递,这个过程中也可以进行值传递
可以看到作为属性传值也可以达到作为参数的效果,但是作为参数就更简单,这里可能需要了解的就是,参数的作用。
3.作为返回值的时候一般用在链式编程里面
-(block)eat{
return self
}
最核心的思想就是返回的对象是方法本身,所以可以一直调用 self.方法.方法.方法
比较熟悉的就是masonry框架里面的写法就是这样,感兴趣的自行搜索一下.
个人学习笔记,希望能对你也有帮助,有错误的地方的话可以指出来.