Block解析

关于block在内存中的位置:

OC中,一般Block就分为以下3种,_NSConcreteStackBlock,_NSConcreteMallocBlock,_NSConcreteGlobalBlock。

先来说明一下3者的区别。

1.从捕获外部变量的角度上来看(注意:MRC下和ARC下_NSConcreteStackBlock和_NSConcreteMallocBlock不一样,ARC下绝大部分_NSConcreteStackBlock类型的block被转换成了_NSConcreteMallocBlock)

  • _NSConcreteStackBlock:
    只用到外部局部变量、成员属性变量,且没有强指针引用的block都是StackBlock。
    StackBlock的生命周期由系统控制的,一旦返回之后,就被系统销毁了。

  • _NSConcreteMallocBlock:
    有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为MallocBlock,没有强指针引用即销毁,生命周期由程序员控制

  • _NSConcreteGlobalBlock:
    没有用到外界变量或只用到全局变量、静态变量的block为_NSConcreteGlobalBlock,生命周期从创建到应用程序结束。

ARC环境下,编译器会自动的判断,把Block自动的从栈copy到堆。比如当Block作为函数返回值的时候,肯定会copy到堆上。

1.手动调用copy
2.Block是函数的返回值
3.Block被强引用,Block被赋值给__strong或者id类型
4.调用系统API入参中含有usingBlcok的方法

以上4种情况,系统都会默认调用copy方法把Block赋复制。

这里再说一下,我们平时使用@weakify和@strongify的原理:

@weakify(self);
self.block = ^(){
    @strongify(self);
    ...
};

上边的代码,等价于:

__weak typeof(self)weakSelf = self;
self.block = ^(){
    __strong typeof(weakSelf)strongSelf = weakSelf;
    ...
};

 @weakify和@strongify就是通过一系列的宏定义,最终会转换成类似图二的代码。

@weakify作用:将当前对象声明为weak类型,这样block内部引用当前对象,就不会造成引用计数+1,可以破解循环引用

@strongify作用:相当于声明一个局部的strong对象,指向当前对象。可以保证调用block的时候,在block整个执行过程中内部的self对象不会释放。因为是局部变量,所以,在整个block执行完之前是不会被释放的,而当block执行完之后会自动释放,这样也防止了总是持有self对象而引发的循环引用。

总结

  • block在C语言层面就是结构体,结构体存储了函数指针和捕获的变量列表
  • block分为全局,栈上,堆上三种,ARC开启的时候,会自动把栈上的block拷贝到堆上
  • __block变量在C语言层面也是一个结构体
  • block捕获在堆中创建的对象的时候会增加对象的引用计数。
  • Block不允许修改外部变量的值,这里所说的外部变量,指的是在栈中分配的变量。

参考文章:

深入研究Block捕获外部变量和__block实现原理

iOS中__block 关键字的底层实现原理

发布了89 篇原创文章 · 获赞 92 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/u013602835/article/details/80795592
今日推荐