美文网首页
简单写一下Block的实质

简单写一下Block的实质

作者: 深海时代 | 来源:发表于2019-03-09 10:32 被阅读0次

    (本人的文章只说个人理解,如有错漏,不吝指正,感谢)

    定义:带有自动变量的匿名函数。

    这里我有两个问题,自动变量和匿名函数。

    我们先研究他的函数再研究他的变量,所以先说匿名函数:

    block其实就是普通的C函数,C函数是支持以指针形式访问的,但是C函数不支持方法不命名。

    C函数的指针访问

    如图,Block的匿名实现其实就是隐去了声明(int func(int num))与指针赋值(int(*funcMB)(int) =&func;)的过程,内部必然是同样需要函数名的,OC基于C。

    Block隐去声明之后只能指针访问,那他同样需要声明指针,所以会有一步(typedef void(^func_Mirror)(int num);)的过程,他并不是声明指针,他是声明指针格式,等价于(int (* funcMB)(int))。如此就可以通过OC提供的匿名创建方法创建C方法并得到指定格式的指针。

    我们来梳理一下Block的流程:

    1.先声明匿名函数的指针类型,typedefvoid(^func_Mirror)(intnum);(此时并不具备函数实体,就像OC方法的声明与实现)

    2.赋值并返回指针,_block=^(int num){};(此时初始化C函数并传入上下文)

    3.通过指针传入参数并执行此C函数,_block(10);(这里的上下文与参数并不是相同的概念,上下文关系到函数的实现,在函数初始化时即确定上下文实际值,而函数初始化与实参是没有任何关系的,实参只需要在函数执行时传入)

    测试代码 结果

    由此,i在block初始化时被copy到C函数体中,与后续的i再无关系,而参数则会在每次执行block时都读取;

    到这里,关于匿名的部分我的理解就说完了。

    __block

    1.普通的上下文变量无法被重新赋值,否则会编译不通过,这是因为上下文在block初始化的时候就需要确定值,使用OC的对象类型可以在block内部调用方法改变其值,block引用OC对象本质上是使用其指针,OC对象调用方法不会改变自身指针而是改变自身结构中的值,所以也就没有修改block的上下文,如果在block内部试图重新赋值OC指针,编译报错;

    2.__block会让原类型变成__Block_byref_val类型,原值传入此类型作为属性,此类型变量成为block成员属性,block将通过copy与dispose管理其内存。(__Block_byref_val 是系统固有类型,非动态生成,只是动态生成此类对象)

    内存

    Block内部存在isa指针,本质上是OC对象的一种,它的class分为三种:_NSConcreteStackBlock,_NSConcreteGlobalBlock,_NSConcreteMallocBlock;

    实现在方法内的是_NSConcreteStackBlock,实现在方法外的是_NSConcreteGlobalBlock,_NSConcreteMallocBlock由_NSConcreteStackBlock copy生成。

    _NSConcreteStackBlock:写在方法里,存在栈上,使用时copy到堆,内部变量的 __forwarding(__block类型变量的self指针)指向堆,出方法废弃;

    _NSConcreteMallocBlock:不显式声明,存在堆里,由栈block copy而来,copy时copy所有变量并引用,被其他对象引用,服从OC内存管理;

    _NSConcreteGlobalBlock:写在方法外,存在.data区,无法截获自动变量,代码执行时声明,代码结束时释放,不需要内存管理。

    copy

    栈block使用时会自动调用copy方法复制到堆;例如:调用,返回,手动调用copy,retain,赋值等等;

    例外情况:block作为参数传给方法时(参数被usingBlock修饰或GCD方法除外)

    手动调起copy时:

    堆block :引用计数+1; 栈block :copy到堆; 全局block :什么都不做;

    __autoreleasing 与__block冲突;

    循环引用(针对OC对象)

    block内变量(或变量的方法与属性)与block互相持有会引起循环引用。

    解决:__weak可以使block不持有对应变量,但变量可能提前释放,block不安全;

    不用修饰词,相当于__strong,只要在block执行完毕之后将其置nil 就可以打破block对其的引用,但变量不安全,block外部,此变量也被置nil,其次有的变量(self)无法被置nil;

    __block,__block会使block引用相对应的block属性,block属性与对应属性与block依然是循环引用,但可以通过给block属性赋值nil打破此循环,手动赋值nil保证变量不被提前释放,缺点,只有block属性被置nil时循环引用才被打破;

    MRC/ARC

    以上均是默认ARC环境下的结论,MRC下,__block使block不会retain(强引用)对应变量,主要用于避免循环引用。

    相关文章

      网友评论

          本文标题:简单写一下Block的实质

          本文链接:https://www.haomeiwen.com/subject/xfsyjqtx.html