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…