block使用修饰符

575 阅读2分钟

block 简介

block其实就是一个代码块,把你想要执行的代码封装在这个代码块里,等到需要的时候再去调用。block是OC对象。

block 的本质

通过clang编译,我们可以看到block的内存布局,就是一个结构体,里面包含一个我么熟悉的isa指针,显然就是一个oc对象。它的底层结构就是:

block的分类

通过class方法我们可以看到block有3种类型
NSGlobalBlock : 存放在数据段,没有访问auto变量(局部变量)的block(基本没啥用)

    // 没用变量或者全局静态变量
    static int c = 5;
    float (^sum)(float, float) = ^(float a, float b){
        return a + b + c;
     };

NSStackBlock:存放在栈区,访问了auto变量

    // 不使用__block时,变量c在block中取值为5,c值改变不影响block中c的值
    int c = 5;
    // __block int c = 5;
    float (^sum)(float, float) = ^(float a, float b){
        return a + b + c;
     };

NSMallocBlock:存放在堆区,NSStackBlock通过copy,从栈区拷贝到堆区

    __block int c = 5;
    float (^sum)(float, float) =[ ^(float a, float b){
        return a + b + c;
     } copy];
  • 每一种block被copy后的结果:

  • block 修饰符 在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上。 MRC下block属性的建议写法
    @property (copy, nonatomic) void (^block)(void);

ARC下block属性的建议写法
@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);

__block

当block捕获auto变量的时候,只是获取了它的值,没有获取到它的地址,所以不能进行修改。
那么我们都知道为了解决block无法修改auto变量的问题,需要用到__block来修饰auto变量。
被__block 修饰过的auto变量会生成一个结构体

  • __block总结
    1.__block可以用于解决block内部无法修改auto变量值的问题
    2.__block不能修饰全局变量,静态变量
    3.编译器会将__block变量包装成一个对象

  • __block的内存管理 当block在栈上,并不会对__block变量产生强引用
    当block被拷贝到堆时
    1.会调用block内部的copy函数
    2.copy函数会调用_Block_object_assign函数
    3._Block_object_assign函数会对__block变量行程强引用

  • 当block从堆中移除时
    1.会调用block内部的disease函数
    2.dispose函数内部会调用_Block_object_dispose函数
    3._Block_object_dispose函数会自动释放饮用的__block变量

__block 的__forwarding指针

block的循环引用

block在copy到堆上是,会持有A的对象c,对象c属于A,因此block也会持有A,从而造成循环引用。

    c = @"qing";
    __weak typeof(self) weakSelf = self;
    B.Tbolck = ^(float a, float b){
        //__weak 转为 __strong 不会造成self的引用计数+1
        __strong typeof(weakSelf) strongSelf = weakSelf;
        strongSelf.c = @"hong";
     } ;

参考资料:
www.jianshu.com/p/e48f30b41…
www.jianshu.com/p/a6c802ffc…
www.jianshu.com/p/560c4a3f9…